From 8208b6fc8fd39dfa4f6cde11e77f1aabb8606a3f Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Mon, 12 Aug 2024 17:00:37 +0530 Subject: [PATCH 01/29] hcm v1.5 : dev to master (#855) * Hlm 6385 irs changes (#841) * HLM-6385: added changes for IRS activity track and closed household concepts * HLM-6385: added changes for IRS activity track and closed household concepts, added db migration script, validations for closed household * HLM-6385: added changes for location tracking * HLM-6385: added changes for location points * HLM-6385: added clientReferenceId and tenantId in LocationPoint, updated Location_capture model * HLM-6385, HCMPRE-46: Updated changes as per design review * HLM-6385, HCMPRE-46: Added Location capture changes * HLM-6385, HCMPRE-46: Added UserAction changes * HLM-6385, HCMPRE-46: updated common models, replaced digit models with service-common * Revert "HLM-6385, HCMPRE-46: updated common models, replaced digit models with service-common" This reverts commit 6abdea41edc35ce8fe9efe298438c559a664136e. * HLM-6385, HCMPRE-46: updated table informations and columns for migration scripts * reverting BoundaryUtil change * reverting BoundaryUtil changes * HLM-6385, HCMPRE-46: updated validators and IRSConsumer * HLM-6385, HCMPRE-46: updated validators * HLM-6385, HCMPRE-46: updated project configuration * HLM-6385, HCMPRE-49: updated models to have isDeleted as it is required in common utils enrichment code * HLM-6385, HCMPRE-46: updated the projectid field, added notnull annotation * HLM-6385, HCMPRE-46: updated all the changes related to enrichment * HLM-6385, HCMPRE-46: made action field notnull * HLM-6385, HCMPRE-46: updated locationCapture and userAction with mandatory latitude, longitude, locationAccuracy fields * HLM-6385, HCMPRE-46: updated locationCapture and userAction with mandatory latitude, longitude, locationAccuracy fields, HCMPRE-116, HCMPRE-117 * HLM-6385, HCMPRE-46: updated locationCapture and userAction with mandatory latitude, longitude, locationAccuracy fields, HCMPRE-116, HCMPRE-117, added in services * HLM-6385, HCMPRE-46: removed outdated changes from Task.java * removed all user location models * Refactored from LocationCapture model to UserAction and packges from irs to useraction * HLM-6385 - lat/long irs name changes * HLM Downsync Incremental product changes pull from impel (#831) * HLM Downsync Incremental product changes pull from impel * HLM removed impel specific changes * renamed Project type filter code constant * HLM updated beneficiary based search * HLM updated downsync search, cycles is required only when it is smc based campaign * HCM - removed project task resource quantity validator * HLM updated downsync logic as per review comments * HCMPRE-216 : Added Administration failed status for validation when task resource is empty or when status is ADMINISTRATION_FAILED * HCMPRE-216: updated task status * HCMPRE-216: changed to ADMINISTRATION_FAILED * HLM-6385: updated with code review comments * HLM-6385: added changes as per review comments, and added correct logs wherever required. * HLM-6385: code review comments addressed. * HLM-6385: review comment added for error handling on LocationCaptureRepository * HLM-6385: another batch of coderabbitai code review comments addressed. * HLM-6385: added more logs in repository for useraction and location capture * HLM-6385: updated the code as per code review comments from @kavi-egov --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Holash Chand * Hcmpre 240 (#846) * HLM closed household status * HCMPRE-240: validate no resource task status scenario with configurable statuses * HCMPRE-240: fixed issues related to string trimming * HLM fixed rowversion referral bug, mis placement of rowversion validator * HCMPRE-240: code review changes * HCMPRE-242: updated for null resources and address check * HCMPRE-242: added for proper null check * HCMPRE-242: added checks for task resource where ever applicable * HCMPRE-242: updated taskstatus to enum from string * HCMPRE-242, HCMPRE-240: renamed task's status field to taskStatus field, as there is contradiction with EgovModel status field * HCMPRE-242: fixed dupcalite entity cache issue for existing entity validation during bulk create * HCMPRE-242: updated project test case for taskStatus field contraints changes : not null * HCMPRE-242: fix generic repository code * HCMPRE-242: added taskstatus migration script * HCMPRE-240: updated PtIsResourceEmptyValidator, for task status * HLM-242: added changes as per code review * Revert "HCMPRE-242: added taskstatus migration script", and removed status field from EgovModel, and rename TaskStatus to status This reverts commit 7caf0c43241154bdabc97bc20c876b86d984fdb6. * HCMPRE-240: FIXED all task status reference --------- Co-authored-by: sivajiganesh-dev * HLM rowmapper issue in household, referral fixed (#848) * HLM rowmapper issue in household, referral fixed * HCMPRE-255: updated the changes for household * reverted local changes commit by mistake * added logic for cascading project date updates (#834) * added logic for cascading project date updates * updated application.properties * refactored logic for using ProjectRequest pojo to send message to kafka instead of Ancestor and Descendant Projects pojo * added comments and enhanced search project logic * made public back to private * made more concise the method in project service separated create project map logic * separated concerns of update based on action whether null or updateProjectDates * updated action logic for just test purpose * updated version of health-service-models library * update logic * updated final logic for cascading update project dates based on flag in project request * reverted config * reverted config 2 * added multiple line comments * udpated error messages * HLM fixed issues in useraction existent entity validator (#850) * HLM fixed issues in useraction existent entity validator * updated after code review comments * updated version for hcm v1.5 release (#852) * updated version for hcm v1.5 release * HLM updated the code as per code review from code rabbit * HCMPRE-209: updated code review comments and code documentation --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Holash Chand Co-authored-by: sivajiganesh-dev Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> --- health-services/household/pom.xml | 2 +- .../java/org/egov/household/Constants.java | 2 +- .../validators/HmExistentEntityValidator.java | 47 ++- .../household/HExistentEntityValidator.java | 47 ++- health-services/individual/pom.xml | 2 +- .../validators/IExistentEntityValidator.java | 48 ++- health-services/libraries/docker-compose.yml | 67 ---- .../health-services-common/CHANGELOG.md | 3 + .../libraries/health-services-common/pom.xml | 2 +- .../data/repository/GenericRepository.java | 19 ++ .../health-services-models/CHANGELOG.md | 6 + .../libraries/health-services-models/pom.xml | 2 +- .../egov/common/models/core/EgovModel.java | 3 - .../common/models/project/ProjectRequest.java | 4 + .../org/egov/common/models/project/Task.java | 17 +- .../common/models/project/TaskStatus.java | 99 ++++++ .../common/models/project/UserActionEnum.java | 33 ++ .../models/project/useraction/UserAction.java | 109 ++++++ .../useraction/UserActionBulkRequest.java | 64 ++++ .../useraction/UserActionBulkResponse.java | 70 ++++ .../project/useraction/UserActionSearch.java | 55 +++ .../useraction/UserActionSearchRequest.java | 44 +++ health-services/project/CHANGELOG.md | 2 + health-services/project/pom.xml | 6 +- .../main/java/org/egov/project/Constants.java | 8 + .../project/config/ProjectConfiguration.java | 33 ++ .../project/consumer/UserActionConsumer.java | 103 ++++++ .../repository/LocationCaptureRepository.java | 135 ++++++++ .../repository/UserActionRepository.java | 139 ++++++++ .../rowmapper/LocationCaptureRowMapper.java | 91 +++++ .../rowmapper/ProjectTaskRowMapper.java | 3 +- .../rowmapper/UserActionRowMapper.java | 94 +++++ .../service/LocationCaptureService.java | 222 ++++++++++++ .../egov/project/service/ProjectService.java | 204 ++++++++++- .../project/service/ProjectTaskService.java | 8 +- .../project/service/UserActionService.java | 213 ++++++++++++ .../service/enrichment/ProjectEnrichment.java | 188 +++++++++- .../ProjectTaskEnrichmentService.java | 29 +- .../UserActionEnrichmentService.java | 67 ++++ .../org/egov/project/util/BoundaryUtil.java | 2 +- .../egov/project/util/ProjectConstants.java | 30 +- .../egov/project/util/ProjectServiceUtil.java | 62 ++++ .../PbExistentEntityValidator.java | 64 ++-- .../task/PtExistentEntityValidator.java | 67 ++-- .../task/PtIsResouceEmptyValidator.java | 57 ++-- .../task/PtNonExistentEntityValidator.java | 8 +- .../task/PtResourceQuantityValidator.java | 11 +- .../useraction/UaBoundaryValidator.java | 125 +++++++ .../useraction/UaExistentEntityValidator.java | 99 ++++++ .../UaNonExistentEntityValidator.java | 96 ++++++ .../useraction/UaNullIdValidator.java | 27 ++ .../useraction/UaProjectIdValidator.java | 96 ++++++ .../useraction/UaRowVersionValidator.java | 69 ++++ .../LocationCaptureController.java | 130 +++++++ .../web/controllers/UserActionController.java | 162 +++++++++ .../src/main/resources/application.properties | 13 + .../V20240711175300__user_location_ddl.sql | 23 ++ .../main/V20240711175500__user_action_ddl.sql | 28 ++ .../egov/project/helper/TaskTestBuilder.java | 8 +- .../referralmanagement/CHANGELOG.md | 4 + health-services/referralmanagement/pom.xml | 4 +- .../egov/referralmanagement/Constants.java | 6 + .../ReferralManagementConfiguration.java | 6 + .../service/DownsyncService.java | 323 +++++++++++------- .../service/MasterDataService.java | 129 +++++++ .../service/ReferralManagementService.java | 6 +- .../validator/RmExistentEntityValidator.java | 62 ++-- .../HfrExistentEntityValidator.java | 56 +-- .../sideeffect/SeExistentEntityValidator.java | 48 ++- health-services/stock/pom.xml | 2 +- .../stock/SExistentEntityValidator.java | 44 ++- .../SrExistentEntityValidator.java | 45 ++- 72 files changed, 3671 insertions(+), 531 deletions(-) delete mode 100644 health-services/libraries/docker-compose.yml create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java create mode 100644 health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java create mode 100644 health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java create mode 100644 health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java create mode 100644 health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java create mode 100644 health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java create mode 100644 health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java create mode 100644 health-services/project/src/main/java/org/egov/project/service/UserActionService.java create mode 100644 health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java create mode 100644 health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql create mode 100644 health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 1d59cc57c94..955934b5e1a 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -45,7 +45,7 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common diff --git a/health-services/household/src/main/java/org/egov/household/Constants.java b/health-services/household/src/main/java/org/egov/household/Constants.java index da512e39234..0ce22b8bb8d 100644 --- a/health-services/household/src/main/java/org/egov/household/Constants.java +++ b/health-services/household/src/main/java/org/egov/household/Constants.java @@ -23,7 +23,7 @@ public interface Constants { String INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD = "INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD"; - String INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD_MESSAGE = "individual is already member od household"; + String INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD_MESSAGE = "individual is already member of household"; String INDIVIDUAL_NOT_FOUND = "INDIVIDUAL_NOT_FOUND"; diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java index 1e335cd753e..cc9eb6c12d7 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -45,39 +45,52 @@ public HmExistentEntityValidator(HouseholdMemberRepository householdMemberReposi /** * Validates the existence of entities with the given client reference IDs. + * This method checks if any of the HouseholdMember entities in the request already exist in the database, + * based on their client reference IDs. If an entity is found to exist, an error is added to the error details map. * * @param request The bulk request containing HouseholdMember entities. - * @return A map containing HouseholdMember entities and their associated error details. + * @return A map containing HouseholdMember entities and their associated error details, if any. */ @Override public Map> validate(HouseholdMemberBulkRequest request) { - // Map to hold HouseholdMember entities and their error details + // Map to hold HouseholdMember entities and their associated error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of HouseholdMember entities from the request List entities = request.getHouseholdMembers(); - // Extract client reference IDs from HouseholdMember entities without errors + + // Extract client reference IDs from HouseholdMember entities that do not have errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(HouseholdMember::getClientReferenceId) - .collect(Collectors.toList()); + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(HouseholdMember::getClientReferenceId) // Map to client reference IDs + .collect(Collectors.toList()); // Collect the IDs into a list + // Create a search object for querying entities by client reference IDs HouseholdMemberSearch householdSearch = HouseholdMemberSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Create a map of client reference ID to HouseholdMember entity for easy lookup + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Check if the client reference ID list is not empty before querying the database if (!CollectionUtils.isEmpty(clientReferenceIdList)) { // Query the repository to find existing entities by client reference IDs - List existentEntities = householdMemberRepository.findById( - clientReferenceIdList, - getIdFieldName(householdSearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + List existingClientReferenceIds = + householdMemberRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for uniqueness + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the HouseholdMember entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing HouseholdMember entities and their associated error details return errorDetailsMap; } - } diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java index 57162432093..33253089919 100644 --- a/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -24,6 +24,7 @@ /** * Validator class for checking the existence of entities with the given client reference IDs. * This validator checks if the provided household entities already exist in the database based on their client reference IDs. + * * @author kanishq-egov */ @Component @@ -44,38 +45,52 @@ public HExistentEntityValidator(HouseholdRepository householdRepository) { /** * Validates the existence of entities with the given client reference IDs. + * This method checks if any of the household entities in the request already exist in the database, + * based on their client reference IDs. If an entity is found to exist, an error is added to the error details map. * * @param request The bulk request containing household entities. - * @return A map containing household entities and their associated error details. + * @return A map containing household entities and their associated error details, if any. */ @Override public Map> validate(HouseholdBulkRequest request) { - // Map to hold household entities and their error details + // Map to hold household entities and their associated error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of household entities from the request List entities = request.getHouseholds(); - // Extract client reference IDs from household entities without errors + + // Extract client reference IDs from household entities that do not have errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(Household::getClientReferenceId) - .collect(Collectors.toList()); + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(Household::getClientReferenceId) // Map to client reference IDs + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map of client reference ID to Household entity for easy lookup + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + // Create a search object for querying entities by client reference IDs HouseholdSearch householdSearch = HouseholdSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database if (!CollectionUtils.isEmpty(clientReferenceIdList)) { // Query the repository to find existing entities by client reference IDs - List existentEntities = householdRepository.findById( - clientReferenceIdList, - getIdFieldName(householdSearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + List existingClientReferenceIds = + householdRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for uniqueness + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the household entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing household entities and their associated error details return errorDetailsMap; } diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index f739e08e736..ab7767c7206 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -53,7 +53,7 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java index a5f75eaa0b8..39bb06f6ed8 100644 --- a/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java +++ b/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -24,6 +24,7 @@ /** * Validator class for checking the existence of entities with the given client reference IDs. * This validator checks if the provided individual entities already exist in the database based on their client reference IDs. + * * @author kanishq-egov */ @Component @@ -44,40 +45,53 @@ public IExistentEntityValidator(IndividualRepository individualRepository) { /** * Validates the existence of entities with the given client reference IDs. + * This method checks if any of the individual entities in the request already exist in the database, + * based on their client reference IDs. If an entity is found to exist, an error is added to the error details map. * * @param request The bulk request containing individual entities. - * @return A map containing individual entities and their associated error details. + * @return A map containing individual entities and their associated error details, if any. */ @Override public Map> validate(IndividualBulkRequest request) { - // Map to hold individual entities and their error details + // Map to hold individual entities and their associated error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of individual entities from the request List entities = request.getIndividuals(); - // Extract client reference IDs from individual entities without errors + + // Extract client reference IDs from individual entities that do not have errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(Individual::getClientReferenceId) - .collect(Collectors.toList()); + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(Individual::getClientReferenceId) // Map to client reference IDs + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map of client reference ID to Individual entity for easy lookup + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + // Create a search object for querying entities by client reference IDs IndividualSearch individualSearch = IndividualSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database if (!CollectionUtils.isEmpty(clientReferenceIdList)) { // Query the repository to find existing entities by client reference IDs - List existentEntities = individualRepository.findById( - clientReferenceIdList, - getIdFieldName(individualSearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + List existingClientReferenceIds = + individualRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for uniqueness + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing individual entities and their associated error details return errorDetailsMap; } } - diff --git a/health-services/libraries/docker-compose.yml b/health-services/libraries/docker-compose.yml deleted file mode 100644 index fea4de2e4ca..00000000000 --- a/health-services/libraries/docker-compose.yml +++ /dev/null @@ -1,67 +0,0 @@ -version: '2' -services: - zookeeper: - image: 'confluentinc/cp-zookeeper:latest' - container_name: zookeeper - environment: - ZOOKEEPER_CLIENT_PORT: 2181 - ZOOKEEPER_TICK_TIME: 2000 - ports: - - '2181:2181' - kafka: - image: 'confluentinc/cp-kafka:latest' - container_name: kafka - depends_on: - - zookeeper - ports: - - '9092:9092' - environment: - KAFKA_BROKER_ID: 1 - KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 - KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://127.0.0.1:9092 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT - KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 - schema-registry: - image: confluentinc/cp-schema-registry:4.1.1 - hostname: schema-registry - ports: - - "38081:38081" - depends_on: - - kafka - environment: - SCHEMA_REGISTRY_KAFKASTORE_CONNECTION_URL: zookeeper:2181 - SCHEMA_REGISTRY_HOST_NAME: schema-registry - SCHEMA_REGISTRY_LISTENERS: http://schema-registry:38081 - SCHEMA_REGISTRY_DEBUG: "true" - - kafka-rest: - image: confluentinc/cp-kafka-rest:4.1.1 - hostname: kafka-rest - ports: - - "38082:38082" - depends_on: - - schema-registry - environment: - KAFKA_REST_ZOOKEEPER_CONNECT: zookeeper:2181 - KAFKA_REST_SCHEMA_REGISTRY_URL: schema-registry:38081 - KAFKA_REST_HOST_NAME: kafka-rest - KAFKA_REST_LISTENERS: http://kafka-rest:38082 - postgres: - image: postgres:10-bullseye - environment: - - POSTGRES_USER=postgres - - POSTGRES_PASSWORD=postgres - ports: - - 5432:5432 - magic: - image: digitsy/kafka-magic - ports: - - "9999:80" - environment: - KMAGIC_ALLOW_TOPIC_DELETE: "true" - KMAGIC_ALLOW_SCHEMA_DELETE: "true" - redis: - image: redis:3.2 - ports: - - 6379:6379 diff --git a/health-services/libraries/health-services-common/CHANGELOG.md b/health-services/libraries/health-services-common/CHANGELOG.md index 14669d15d9f..fbb085523fc 100644 --- a/health-services/libraries/health-services-common/CHANGELOG.md +++ b/health-services/libraries/health-services-common/CHANGELOG.md @@ -1,5 +1,8 @@ All notable changes to this module will be documented in this file. +## 1.0.18 - 2024-08-09 +- Added validateClientReferenceIdsFromDB method to GenericRepository. + ## 1.0.16 - 2024-05-29 - Introduced multiple reusable functions to streamline and simplify the codebase. - Enhanced function modularity for better maintainability and readability. diff --git a/health-services/libraries/health-services-common/pom.xml b/health-services/libraries/health-services-common/pom.xml index a48b96a222d..8f5e0d4fae9 100644 --- a/health-services/libraries/health-services-common/pom.xml +++ b/health-services/libraries/health-services-common/pom.xml @@ -8,7 +8,7 @@ health-services-common jar health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT Shared classes among services diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java index 872d11c9d2a..537a82400cc 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java @@ -291,4 +291,23 @@ public List validateIds(List idsToValidate, String columnName){ return validIds.stream().map((obj) -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList()); } + + public List validateClientReferenceIdsFromDB(List clientReferenceIds, Boolean isDeletedKeyPresent) { + List objFound = new ArrayList<>(); + + String query = null; + + if(isDeletedKeyPresent) { + query = String.format("SELECT clientReferenceId FROM %s WHERE clientReferenceId IN (:ids) AND isDeleted = false", tableName); + } else { + query = String.format("SELECT clientReferenceId FROM %s WHERE clientReferenceId IN (:ids) ", tableName); + } + + Map paramMap = new HashMap<>(); + paramMap.put("ids", clientReferenceIds); + + objFound.addAll(namedParameterJdbcTemplate.queryForList(query, paramMap, String.class)); + + return objFound; + } } diff --git a/health-services/libraries/health-services-models/CHANGELOG.md b/health-services/libraries/health-services-models/CHANGELOG.md index 531680fc20e..c7476cbe79b 100644 --- a/health-services/libraries/health-services-models/CHANGELOG.md +++ b/health-services/libraries/health-services-models/CHANGELOG.md @@ -1,5 +1,11 @@ All notable changes to this module will be documented in this file. +## 1.0.21 - 2024-08-07 +- Added UserActionEnum, UserAction Entities, TaskStatus enum +- Added isCascadingProjectDateUpdate in ProjectRequest model +- Removed status field from EgovModel + + ## 1.0.20 - 2024-05-29 - Added EgovModel, EgovSearchModel, EgovOfflineModel, EgovOfflineSearchModel - Updated Lombok to 1.18.22 for SuperBuilder annotation support. diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index ccbf98bc824..6ca95c3fe47 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.21-SNAPSHOT 17 ${java.version} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java index d125458f9af..f68ea5cea75 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java @@ -30,9 +30,6 @@ public class EgovModel { @Size(min = 2, max = 1000) protected String tenantId; - @JsonProperty("status") - protected String status; - @JsonProperty("source") protected String source; //TODO what are the various sources and needs comments diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java index fd09b6b635b..da4ae0343e4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java @@ -38,6 +38,10 @@ public class ProjectRequest { @Size(min=1) private List projects = new ArrayList<>(); + @JsonProperty("isCascadingProjectDateUpdate") + @Valid + private boolean isCascadingProjectDateUpdate = false; + @JsonProperty("apiOperation") @Valid private ApiOperation apiOperation = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index eddbeb82f0f..9f0160c34b5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -1,9 +1,13 @@ package org.egov.common.models.project; -import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -12,12 +16,6 @@ import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * Task */ @@ -75,7 +73,8 @@ public class Task extends EgovOfflineModel { private Boolean isDeleted = Boolean.FALSE; @JsonProperty("status") - private String status = null; + @NotNull + TaskStatus status = null; public Task addResourcesItem(TaskResource resourcesItem) { this.resources.add(resourcesItem); diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java new file mode 100644 index 00000000000..a17652a89c0 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java @@ -0,0 +1,99 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Enum representing the various possible statuses for a task. + *

+ * Each status corresponds to a specific state of the task in the system. + * The status is stored as a string value and can be serialized/deserialized + * from JSON using Jackson annotations. + *

+ */ +public enum TaskStatus { + + /** + * Indicates that the task administration has failed. + * This status represents an error or issue encountered during + * the administrative process of the task. + */ + ADMINISTRATION_FAILED("ADMINISTRATION_FAILED"), + + /** + * Indicates that the task administration was successful. + * This status signifies that the task has been processed correctly + * without any issues. + */ + ADMINISTRATION_SUCCESS("ADMINISTRATION_SUCCESS"), + + /** + * Indicates that the beneficiary has refused the task. + * This status means that the individual or entity for whom the task + * was intended has declined to participate or accept it. + */ + BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"), + + /** + * Indicates that the household associated with the task has been closed. + * This status implies that the household is no longer active or + * relevant to the task, possibly due to its closure or other reasons. + */ + CLOSED_HOUSEHOLD("CLOSED_HOUSEHOLD"), + + /** + * Indicates that the task has been delivered. + * This status shows that the task has been successfully completed + * and the deliverables have been provided. + */ + DELIVERED("DELIVERED"), + + /** + * Indicates that the task has not been administered. + * This status signifies that the task has not been processed or + * handled yet. + */ + NOT_ADMINISTERED("NOT_ADMINISTERED"); + + // The string value associated with the task status. + private String value; + + /** + * Constructor to initialize the TaskStatus with a specific string value. + * + * @param value The string value representing the task status. + */ + TaskStatus(String value) { + this.value = value; + } + + /** + * Returns the string representation of the TaskStatus. + * This method is used for serialization of the enum value to JSON. + * + * @return The string value of the task status. + */ + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + /** + * Creates a TaskStatus enum from a string value. + * This method is used for deserialization of the enum value from JSON. + * + * @param text The string value representing the task status. + * @return The TaskStatus enum corresponding to the provided value, + * or null if no match is found. + */ + @JsonCreator + public static TaskStatus fromValue(String text) { + for (TaskStatus status : TaskStatus.values()) { + if (String.valueOf(status.value).equals(text)) { + return status; + } + } + return null; // Return null if no matching status is found + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java new file mode 100644 index 00000000000..1271584b583 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java @@ -0,0 +1,33 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum UserActionEnum { + CLOSED_HOUSEHOLD("CLOSED_HOUSEHOLD"), + LOCATION_CAPTURE("LOCATION_CAPTURE"), + OTHER("OTHER"); + + private String value; + + UserActionEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static UserActionEnum fromValue(String text) { + for (UserActionEnum status : UserActionEnum.values()) { + if (String.valueOf(status.value).equals(text)) { + return status; + } + } + return null; + } + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java new file mode 100644 index 00000000000..d58d98996d8 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java @@ -0,0 +1,109 @@ +package org.egov.common.models.project.useraction; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; +import org.egov.common.models.project.UserActionEnum; +import org.springframework.validation.annotation.Validated; + +/** + * The UserAction class represents an action performed by the logged in user related to a project with + * or without in relation to a beneficiary + * It extends the EgovOfflineModel to inherit common properties. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserAction extends EgovOfflineModel { + + /** + * The ID of the project associated with the user action. + * It must be between 2 and 64 characters long and cannot be null. + */ + @JsonProperty("projectId") + @Size(min = 2, max = 64, message = "Project ID must be between 2 and 64 characters") + @NotNull + private String projectId; + + /** + * The latitude coordinate of the user action's location. + * It must be between -90 and 90 degrees and cannot be null. + */ + @JsonProperty("latitude") + @DecimalMin("-90") + @DecimalMax("90") + @NotNull + private Double latitude; + + /** + * The longitude coordinate of the user action's location. + * It must be between -180 and 180 degrees and cannot be null. + */ + @JsonProperty("longitude") + @DecimalMin("-180") + @DecimalMax("180") + @NotNull + private Double longitude; + + /** + * The accuracy of the location measurement in meters. + * It must be a positive number and cannot be null. + */ + @JsonProperty("locationAccuracy") + @DecimalMin("0") + @NotNull + private Double locationAccuracy; + + /** + * The code of the boundary where the user action took place. + * It cannot be null. + */ + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode; + + /** + * The action performed by the user, represented as a UserActionEnum object. + * It cannot be null. + */ + @JsonProperty("action") + @NotNull + private UserActionEnum action; + + /** + * An optional tag if there is a beneficiary associated with the user action + * It must be between 2 and 64 characters long. + */ + @JsonProperty("beneficiaryTag") + @Size(min = 2, max = 64) + private String beneficiaryTag; + + /** + * An optional tag for the resource associated with the user action. + * It must be between 2 and 64 characters long. + */ + @JsonProperty("resourceTag") + @Size(min = 2, max = 64) + private String resourceTag; + + /** + * A flag indicating whether the user action has been deleted. + * The default value is false. + */ + @JsonProperty("isDeleted") + @Builder.Default + private Boolean isDeleted = false; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java new file mode 100644 index 00000000000..b2bcb8b4f11 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java @@ -0,0 +1,64 @@ +package org.egov.common.models.project.useraction; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionBulkRequest class is used for handling bulk requests of user actions. + * It contains a RequestInfo object and a list of UserAction objects. + */ +@Validated + + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionBulkRequest { + + /** + * The RequestInfo object containing metadata about the request. + * This field is mandatory and must be valid. + */ + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + /** + * A list of UserAction objects that are part of the bulk request. + * This field is mandatory, must contain at least one item, and must be valid. + * It is initialized to an empty list by default. + */ + @JsonProperty("UserActions") + @NotNull + @Valid + @Size(min = 1) + @Builder.Default + private List userActions = new ArrayList<>(); + + /** + * Adds a UserAction item to the list of user actions in the bulk request. + * This method is useful for incrementally building the list of user actions. + * + * @param userAction The UserAction object to be added to the list. + * @return The current instance of UserActionBulkRequest with the new UserAction added. + */ + public UserActionBulkRequest addTaskItem(UserAction userAction) { + this.userActions.add(userAction); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java new file mode 100644 index 00000000000..f8698b676bd --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java @@ -0,0 +1,70 @@ +package org.egov.common.models.project.useraction; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionBulkResponse class is used for handling bulk responses of user actions. + * It contains a ResponseInfo object, a total count of user actions, and a list of UserAction objects. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionBulkResponse { + + /** + * The ResponseInfo object containing metadata about the response. + * This field is mandatory and must be valid. + */ + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + /** + * The total count of user actions in the response. + * It is initialized to 0 by default. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * A list of UserAction objects that are part of the bulk response. + * This field is mandatory and must be valid. + */ + @JsonProperty("UserActions") + @NotNull + @Valid + private List userActions = null; + + /** + * Adds a UserAction item to the list of user actions in the bulk response. + * This method is useful for incrementally building the list of user actions. + * + * @param userActionItem The UserAction object to be added to the list. + * @return The current instance of UserActionBulkResponse with the new UserAction added. + */ + public UserActionBulkResponse addUserAction(UserAction userActionItem) { + if (this.userActions == null) { + this.userActions = new ArrayList<>(); + } + this.userActions.add(userActionItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java new file mode 100644 index 00000000000..0e2051b6be6 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java @@ -0,0 +1,55 @@ +package org.egov.common.models.project.useraction; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionSearch class is used for searching user actions based on various criteria. + * It extends the EgovOfflineSearchModel to inherit common search properties. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionSearch extends EgovOfflineSearchModel { + + /** + * A userId to filter the user actions. + */ + @JsonProperty("createdBy") + private String createdBy; + + /** + * A project ID to filter the user actions. + */ + @JsonProperty("projectId") + private String projectId; + + /** + * A beneficiary tag to filter the user actions. + */ + @JsonProperty("beneficiaryTag") + private String beneficiaryTag; + + /** + * A resource tag to filter the user actions. + */ + @JsonProperty("resourceTag") + private String resourceTag; + + /** + * A boundary code to filter the user actions. + */ + @JsonProperty("boundaryCode") + private String boundaryCode; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java new file mode 100644 index 00000000000..1bf43eb8ced --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java @@ -0,0 +1,44 @@ +package org.egov.common.models.project.useraction; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionSearchRequest class is used to encapsulate the request information + * for searching user actions. It includes the request metadata and the search criteria. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionSearchRequest { + + /** + * The RequestInfo object contains metadata about the request, such as the + * API version, request timestamp, and user details. This field is mandatory + * and must be valid. + */ + @JsonProperty("RequestInfo") + @NotNull + @Valid + private org.egov.common.contract.request.RequestInfo requestInfo; + + /** + * The UserAction object contains the search criteria for filtering user actions. + * This includes various filters such as project IDs, beneficiary tags, resource tags, + * and boundary codes. This field is mandatory and must be valid. + */ + @JsonProperty("UserAction") + @NotNull + @Valid + private UserActionSearch userAction; +} \ No newline at end of file diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 427aa3e5917..7865206457c 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -1,5 +1,7 @@ All notable changes to this module will be documented in this file. +## 1.1.5 - 2024-08-07 +- Added UserAction functionality with support for Location capture. ## 1.1.4 - 2024-05-29 - Integrated Core 2.9LTS diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 54bd4fd9c91..fd0b688dcc3 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -5,7 +5,7 @@ project jar project - 1.1.4 + 1.1.5 17 ${java.version} @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.21-SNAPSHOT compile diff --git a/health-services/project/src/main/java/org/egov/project/Constants.java b/health-services/project/src/main/java/org/egov/project/Constants.java index 91e1f824ae8..66333c64989 100644 --- a/health-services/project/src/main/java/org/egov/project/Constants.java +++ b/health-services/project/src/main/java/org/egov/project/Constants.java @@ -56,4 +56,12 @@ public interface Constants { String TASK_QUANTITY = "taskQuantity"; + String HOUSEHOLD_ID = "HouseholdId"; + + String SET_USER_ACTION = "setUserActions"; + + String GET_USER_ACTION = "getUserActions"; + + String PROJECT_USER_ACTION_ENRICHMENT_ERROR = "PROJECT_USER_ACTION_ENRICHMENT_ERROR"; + } diff --git a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java index 32c76154f2b..26759e381e2 100644 --- a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java @@ -1,5 +1,7 @@ package org.egov.project.config; +import java.util.List; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -189,4 +191,35 @@ public class ProjectConfiguration { @Value("${project.staff.attendance.topic}") private String projectStaffAttendanceTopic; + @Value("${project.management.system.kafka.update.date.topic}") + private String updateProjectDateTopic; + + + // closed household task + @Value("${project.user.action.kafka.create.topic}") + private String createUserActionTopic; + + @Value("${project.user.action.consumer.bulk.create.topic}") + private String bulkCreateUserActionTopic; + + @Value("${project.user.action.kafka.update.topic}") + private String updateUserActionTopic; + + @Value("${project.user.action.consumer.bulk.update.topic}") + private String bulkUpdateUserActionTopic; + + @Value("${project.location.capture.consumer.bulk.create.topic}") + private String bulkCreateLocationCaptureTopic; + + @Value("${project.location.capture.kafka.create.topic}") + private String createLocationCaptureTopic; + + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; + + @Value("${project.task.no.resource.validation.status}") + private List noResourceStatuses; } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java new file mode 100644 index 00000000000..f01d2e00913 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java @@ -0,0 +1,103 @@ +package org.egov.project.consumer; + +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.project.service.LocationCaptureService; +import org.egov.project.service.UserActionService; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class UserActionConsumer { + + private final UserActionService userActionService; + private final LocationCaptureService locationCaptureService; + private final ObjectMapper objectMapper; + + @Autowired + public UserActionConsumer(UserActionService userActionService, LocationCaptureService locationCaptureService, ObjectMapper objectMapper) { + // Constructor injection for services and object mapper + this.userActionService = userActionService; + this.locationCaptureService = locationCaptureService; + this.objectMapper = objectMapper; + } + + /** + * Kafka listener for bulk creating user actions. + * + * @param consumerRecord The Kafka consumer record as a map. + * @param topic The topic from which the message was received. + * @return List of created UserAction objects. + */ + @KafkaListener(topics = "${project.user.action.consumer.bulk.create.topic}") + public void bulkCreateUserAction(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert consumer record to UserActionBulkRequest object + UserActionBulkRequest request = objectMapper.convertValue(consumerRecord, UserActionBulkRequest.class); + // Call the userActionService to handle the create operation + userActionService.create(request, true); + } catch (Exception exception) { + // Log any exception that occurs + log.error("Error processing bulk create for user actions from topic {}: {}", topic, ExceptionUtils.getStackTrace(exception)); + // throw custom exception + throw new CustomException("PROJECT_USER_ACTION_BULK_CREATE", exception.getMessage()); + } + } + + /** + * Kafka listener for bulk updating user actions. + * + * @param consumerRecord The Kafka consumer record as a map. + * @param topic The topic from which the message was received. + * @return List of updated UserAction objects. + */ + @KafkaListener(topics = "${project.user.action.consumer.bulk.update.topic}") + public void bulkUpdateUserAction(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert consumer record to UserActionBulkRequest object + UserActionBulkRequest request = objectMapper.convertValue(consumerRecord, UserActionBulkRequest.class); + // Call the userActionService to handle the update operation + userActionService.update(request, true); + } catch (Exception exception) { + // Log any exception that occurs + log.error("Error processing bulk update for user actions from topic {}: {}", topic, ExceptionUtils.getStackTrace(exception)); + // throw custom exception + throw new CustomException("PROJECT_USER_ACTION_BULK_UPDATE", exception.getMessage()); + } + } + + /** + * Kafka listener for bulk creating location captures. + * + * @param consumerRecord The Kafka consumer record as a map. + * @param topic The topic from which the message was received. + * @return List of created UserAction objects. + */ + @KafkaListener(topics = "${project.location.capture.consumer.bulk.create.topic}") + public void bulkCreateLocationCapture(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert consumer record to UserActionBulkRequest object + UserActionBulkRequest request = objectMapper.convertValue(consumerRecord, UserActionBulkRequest.class); + // Call the locationCaptureService to handle the create operation + locationCaptureService.create(request, true); + } catch (Exception exception) { + // Log any exception that occurs + log.error("Error processing bulk create for location captures from topic {}: {}", topic, ExceptionUtils.getStackTrace(exception)); + // throw custom exception + throw new CustomException("PROJECT_USER_ACTION_LOCATION_CAPTURE_BULK_CREATE", exception.getMessage()); + } + } + +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java b/health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java new file mode 100644 index 00000000000..9127c0272b8 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java @@ -0,0 +1,135 @@ +package org.egov.project.repository; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.producer.Producer; +import org.egov.common.utils.CommonUtils; +import org.egov.project.repository.rowmapper.LocationCaptureRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdMethod; + +@Repository +@Slf4j +public class LocationCaptureRepository extends GenericRepository { + + private final String selectQuery = "SELECT id, clientreferenceid, tenantid, projectid, latitude, longitude, locationaccuracy, boundarycode, action, createdby, createdtime, lastmodifiedby, lastmodifiedtime, clientcreatedtime, clientlastmodifiedtime, clientcreatedby, clientlastmodifiedby, additionaldetails FROM user_location ul "; + + @Autowired + protected LocationCaptureRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, LocationCaptureRowMapper locationCaptureRowMapper) { + // Initialize the repository with producer, JDBC template, Redis template, query builder, and row mapper + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, locationCaptureRowMapper, Optional.of("user_location")); + } + + /** + * Finds user locations based on search criteria and URL parameters. + * + * @param searchObject The search criteria for user locations. + * @param urlParams The URL parameters including pagination and filtering information. + * @return A SearchResponse containing the list of user locations and the total count. + */ + public SearchResponse find(UserActionSearch searchObject, URLParams urlParams) { + log.info("Executing find with searchObject: {} and urlParams: {}", searchObject, urlParams); + + String query = selectQuery + ""; + + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "ul.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "ul.clientReferenceId IN (:clientReferenceId)"); + + if (CollectionUtils.isEmpty(whereFields)) { + query = query + " WHERE ul.tenantId=:tenantId "; + } else { + query = query + " AND ul.tenantId=:tenantId "; + } + + if (urlParams.getLastChangedSince() != null) { + query = query + " AND ul.lastModifiedTime>=:lastModifiedTime "; + } + paramsMap.put("tenantId", urlParams.getTenantId()); + paramsMap.put("lastModifiedTime", urlParams.getLastChangedSince()); + + try { + log.debug("Executing query to fetch total count"); + Long totalCount = CommonUtils.constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + " ORDER BY ul.id ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", urlParams.getLimit()); + paramsMap.put("offset", urlParams.getOffset()); + + log.debug("Executing query to fetch user locations: {}", query); + List locationCaptureList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + + log.info("Successfully fetched user locations: {}", locationCaptureList.size()); + return SearchResponse.builder().response(locationCaptureList).totalCount(totalCount).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user locations", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } + + /** + * Finds user locations by their IDs, first checking the cache before querying the database. + * + * @param ids The list of IDs to search for. + * @param columnName The name of the column to search by. + * @return A SearchResponse containing the list of user locations found. + */ + public SearchResponse findById(List ids, String columnName) { + log.info("Executing findById with ids: {} and columnName: {}", ids, columnName); + + List objFound = findInCache(ids); + + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + + if (ids.isEmpty()) { + log.info("All requested user locations found in cache"); + return SearchResponse.builder().response(objFound).build(); + } + } + + String query = String.format(selectQuery + " WHERE ul.%s IN (:ids)", columnName); + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + + try { + log.debug("Executing query to fetch user locations by ID: {}", query); + List locationCaptureList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + objFound.addAll(locationCaptureList); + putInCache(objFound); + + log.info("Successfully fetched user locations by ID: {}", locationCaptureList.size()); + return SearchResponse.builder().response(objFound).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user locations by ID", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java b/health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java new file mode 100644 index 00000000000..a5e61318fe8 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java @@ -0,0 +1,139 @@ +package org.egov.project.repository; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.producer.Producer; +import org.egov.common.utils.CommonUtils; +import org.egov.project.repository.rowmapper.UserActionRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdMethod; + +@Repository +@Slf4j +public class UserActionRepository extends GenericRepository { + + private final String selectQuery = + "SELECT id, clientreferenceid, tenantid, projectid, latitude, longitude, locationaccuracy, boundarycode, action, beneficiarytag, resourcetag, status, additionaldetails, createdby, createdtime, lastmodifiedby, lastmodifiedtime, clientcreatedtime, clientlastmodifiedtime, clientcreatedby, clientlastmodifiedby, rowversion FROM user_action ua"; + @Autowired + protected UserActionRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + UserActionRowMapper rowMapper) { + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("user_action")); + } + + /** + * Finds user actions based on search criteria and URL parameters. + * + * @param searchObject The search criteria for user actions. + * @param urlParams The URL parameters including pagination and filtering information. + * @return A SearchResponse containing the list of user actions and the total count. + * @throws QueryBuilderException If there is an error building the query. + */ + public SearchResponse find(UserActionSearch searchObject, URLParams urlParams) throws QueryBuilderException { + log.info("Executing find with searchObject: {} and urlParams: {}", searchObject, urlParams); + + String query = ""+selectQuery; + + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "ua.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "ua.clientReferenceId IN (:clientReferenceId)"); + + if (CollectionUtils.isEmpty(whereFields)) { + query = query + " WHERE ua.tenantId=:tenantId "; + } else { + query = query + " AND ua.tenantId=:tenantId "; + } + + if (urlParams.getLastChangedSince() != null) { + query = query + " AND lastModifiedTime>=:lastModifiedTime "; + } + paramsMap.put("tenantId", urlParams.getTenantId()); + paramsMap.put("isDeleted", urlParams.getIncludeDeleted()); + paramsMap.put("lastModifiedTime", urlParams.getLastChangedSince()); + + try { + log.debug("Executing query to fetch total count"); + Long totalCount = CommonUtils.constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + " ORDER BY ua.id ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", urlParams.getLimit()); + paramsMap.put("offset", urlParams.getOffset()); + + log.debug("Executing query to fetch user actions: {}", query); + List userActionList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + + log.info("Successfully fetched user actions: {}", userActionList.size()); + return SearchResponse.builder().response(userActionList).totalCount(totalCount).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user actions", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } + + /** + * Finds user actions by their IDs, first checking the cache before querying the database. + * + * @param ids The list of IDs to search for. + * @param columnName The name of the column to search by. + * @return A SearchResponse containing the list of user actions found. + */ + public SearchResponse findById(List ids, String columnName) { + log.info("Executing findById with ids: {} and columnName: {}", ids, columnName); + + List objFound = findInCache(ids); + + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + + if (ids.isEmpty()) { + log.info("All requested user actions found in cache"); + return SearchResponse.builder().response(objFound).build(); + } + } + + String query = String.format(selectQuery + " WHERE ua.%s IN (:ids) ", columnName); + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + + try { + log.debug("Executing query to fetch user actions by ID: {}", query); + List userActionList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + objFound.addAll(userActionList); + putInCache(objFound); + + log.info("Successfully fetched user actions by ID: {}", userActionList.size()); + return SearchResponse.builder().response(objFound).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user actions by ID", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java new file mode 100644 index 00000000000..b9ea8babec8 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java @@ -0,0 +1,91 @@ +package org.egov.project.repository.rowmapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.project.UserActionEnum; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +/** + * RowMapper implementation for mapping rows of a ResultSet to UserAction objects. + * This class is used to map the result of a SQL query to UserAction instances. + */ +@Component +@Slf4j +public class LocationCaptureRowMapper implements RowMapper { + + private final ObjectMapper objectMapper; + + /** + * Constructor for dependency injection of ObjectMapper. + * + * @param objectMapper The ObjectMapper used for converting JSON strings to objects. + */ + @Autowired + public LocationCaptureRowMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Map a single row of the ResultSet to a UserAction object. + * + * @param resultSet The ResultSet containing data from the database. + * @param rowNum The number of the current row. + * @return A UserAction object populated with data from the current row of the ResultSet. + * @throws SQLException If there is an issue accessing the ResultSet data. + */ + @Override + public UserAction mapRow(ResultSet resultSet, int rowNum) throws SQLException { + + // Creating AuditDetails object with information from the ResultSet + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + + // Creating client-specific AuditDetails object with information from the ResultSet + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); + + UserAction locationCaptureUserAction; + try { + // Building the UserAction object with data from the ResultSet + locationCaptureUserAction = UserAction.builder() + .id(resultSet.getString("id")) + .tenantId(resultSet.getString("tenantId")) + .clientReferenceId(resultSet.getString("clientReferenceId")) + .projectId(resultSet.getString("projectId")) + .latitude(resultSet.getDouble("latitude")) + .longitude(resultSet.getDouble("longitude")) + .locationAccuracy(resultSet.getDouble("locationAccuracy")) + .boundaryCode(resultSet.getString("boundaryCode")) + .action(UserActionEnum.fromValue(resultSet.getString("action"))) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .build(); + } catch (JsonProcessingException e) { + // Throwing a RuntimeException if there's an error processing JSON + log.error("Error processing Additional detail JSON in Location capture UserAction ", e); + throw new CustomException("HCM_PROJECT_USER_ACTION_LOCATION_CAPTURE_ROW_MAPPER_INVALID_ERROR", "Error processing JSON: " + e.getMessage()); + } + + return locationCaptureUserAction; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index caafec9a8e1..ccff648bd41 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -8,6 +8,7 @@ import org.egov.common.models.project.AddressType; import org.egov.common.models.core.Boundary; import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskStatus; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; @@ -47,7 +48,7 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .plannedEndDate(resultSet.getLong("plannedEndDate")) .actualStartDate(resultSet.getLong("actualStartDate")) .actualEndDate(resultSet.getLong("actualEndDate")) - .status(resultSet.getString("status")) + .status(TaskStatus.fromValue(resultSet.getString("status"))) .auditDetails(auditDetails) .clientAuditDetails(clientAuditDetails) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java new file mode 100644 index 00000000000..8a63f0f3c99 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java @@ -0,0 +1,94 @@ +package org.egov.project.repository.rowmapper; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.project.UserActionEnum; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +/** + * RowMapper implementation for mapping rows of a ResultSet to UserAction objects. + * This class is used to map the result of a SQL query to UserAction instances. + */ +@Component +@Slf4j +public class UserActionRowMapper implements RowMapper { + + private final ObjectMapper objectMapper; + + /** + * Constructor for dependency injection of ObjectMapper. + * + * @param objectMapper The ObjectMapper used for converting JSON strings to objects. + */ + @Autowired + public UserActionRowMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Map a single row of the ResultSet to a UserAction object. + * + * @param resultSet The ResultSet containing data from the database. + * @param rowNum The number of the current row. + * @return A UserAction object populated with data from the current row of the ResultSet. + * @throws SQLException If there is an issue accessing the ResultSet data or processing JSON. + */ + @Override + public UserAction mapRow(ResultSet resultSet, int rowNum) throws SQLException { + try { + // Creating AuditDetails object with information from the ResultSet + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + + // Creating client-specific AuditDetails object with information from the ResultSet + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); + + // Building the UserAction object with data from the ResultSet + UserAction userAction = UserAction.builder() + .id(resultSet.getString("id")) + .tenantId(resultSet.getString("tenantId")) + .clientReferenceId(resultSet.getString("clientReferenceId")) + .projectId(resultSet.getString("projectId")) + .latitude(resultSet.getDouble("latitude")) + .longitude(resultSet.getDouble("longitude")) + .locationAccuracy(resultSet.getDouble("locationAccuracy")) + .boundaryCode(resultSet.getString("boundaryCode")) + .action(UserActionEnum.fromValue(resultSet.getString("action"))) + .beneficiaryTag(resultSet.getString("beneficiaryTag")) + .resourceTag(resultSet.getString("resourceTag")) + .rowVersion(resultSet.getInt("rowVersion")) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .build(); + + return userAction; + } catch (JsonProcessingException e) { + String id = resultSet.getString("id"); + String errorMessage = "Error processing JSON for UserAction mapping. Row number: " + rowNum + ", id: " + (id != null ? id : "not available"); + log.error(errorMessage, e); + throw new CustomException("HCM_PROJECT_USER_ACTION_ROW_MAPPER_INVALID_ERROR", errorMessage + ", " + e.getMessage()); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java b/health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java new file mode 100644 index 00000000000..5667184beb0 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java @@ -0,0 +1,222 @@ +package org.egov.project.service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.ds.Tuple; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.LocationCaptureRepository; +import org.egov.project.service.enrichment.UserActionEnrichmentService; +import org.egov.project.validator.useraction.UaBoundaryValidator; +import org.egov.project.validator.useraction.UaExistentEntityValidator; +import org.egov.project.validator.useraction.UaProjectIdValidator; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.project.Constants.SET_USER_ACTION; +import static org.egov.project.Constants.VALIDATION_ERROR; + +/** + * Service class for handling location capture tasks related to user actions. + * Provides methods for creating, validating, searching, and caching location capture tasks. + */ +@Service +@Slf4j +public class LocationCaptureService { + + private final IdGenService idGenService; + private final LocationCaptureRepository locationCaptureRepository; + private final ServiceRequestClient serviceRequestClient; + private final ProjectConfiguration projectConfiguration; + private final UserActionEnrichmentService userActionEnrichmentService; + private final List> validators; + + /** + * Predicate to determine if a validator is applicable for creation. + * Filters validators based on specific classes. + */ + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(UaProjectIdValidator.class) + || validator.getClass().equals(UaExistentEntityValidator.class) + || validator.getClass().equals(UaBoundaryValidator.class); + + /** + * Constructor for injecting dependencies into the LocationCaptureService. + * + * @param idGenService The service for generating unique IDs. + * @param locationCaptureRepository Repository for location capture tasks. + * @param serviceRequestClient Client for making service requests. + * @param projectConfiguration Configuration properties related to the project. + * @param userActionEnrichmentService Service for enriching location capture user action tasks. + * @param validators List of validators for user actions. + */ + @Autowired + public LocationCaptureService( + IdGenService idGenService, + LocationCaptureRepository locationCaptureRepository, + ServiceRequestClient serviceRequestClient, + ProjectConfiguration projectConfiguration, + UserActionEnrichmentService userActionEnrichmentService, + List> validators + ) { + this.idGenService = idGenService; + this.locationCaptureRepository = locationCaptureRepository; + this.serviceRequestClient = serviceRequestClient; + this.projectConfiguration = projectConfiguration; + this.userActionEnrichmentService = userActionEnrichmentService; + this.validators = validators; + } + + /** + * Creates location capture tasks in bulk. + * Validates the request, enriches valid tasks, saves them, and handles errors. + * + * @param request The bulk request containing location capture tasks. + * @param isBulk Flag indicating if the request is a bulk operation. + * @return A list of valid location capture tasks. + */ + public List create(UserActionBulkRequest request, boolean isBulk) { + log.info("Received request to create bulk location capture tasks"); + + // Validate the request and separate valid tasks from error details. + Tuple, Map> tuple = validate(validators, isApplicableForCreate, request, isBulk); + Map errorDetailsMap = tuple.getY(); + List validLocationCaptures = tuple.getX(); + + try { + if (!validLocationCaptures.isEmpty()) { + log.info("Processing {} valid entities", validLocationCaptures.size()); + + // Enrich valid location capture tasks. + userActionEnrichmentService.create(validLocationCaptures, request); + + // Save valid location capture tasks and send them to the Kafka topic. + locationCaptureRepository.save(validLocationCaptures, projectConfiguration.getCreateLocationCaptureTopic()); + log.info("Successfully created location capture tasks"); + } + } catch (Exception exception) { + // Log and handle exceptions that occur during task creation. + log.error("Error occurred while creating location capture tasks: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validLocationCaptures, exception, SET_USER_ACTION); + } + + // Handle errors based on the validation results. + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validLocationCaptures; + } + + /** + * Validates the user action bulk request using the provided validators. + * Filters out tasks with errors and returns the valid ones. + * + * @param validators List of validators to use for validation. + * @param applicableValidators Predicate to filter applicable validators. + * @param request The bulk request to validate. + * @param isBulk Flag indicating if the request is a bulk operation. + * @return A tuple containing valid location capture tasks and error details. + */ + private Tuple, Map> validate( + List> validators, + Predicate> applicableValidators, + UserActionBulkRequest request, boolean isBulk) { + + log.info("Validating request"); + + // Perform validation and collect error details. + Map errorDetailsMap = CommonUtils.validate( + validators, + applicableValidators, + request, + SET_USER_ACTION + ); + + // Throw an exception if there are validation errors and it's not a bulk operation. + if (!errorDetailsMap.isEmpty() && !isBulk) { + throw new CustomException(VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + + // Filter out tasks with no errors. + List validLocationCaptures = request.getUserActions().stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()); + + return new Tuple<>(validLocationCaptures, errorDetailsMap); + } + + /** + * Searches for location capture tasks based on the provided search request and URL parameters. + * Supports searching by ID or by other criteria. + * + * @param locationCaptureSearchRequest The search request containing criteria for searching. + * @param urlParams URL parameters for filtering the search results. + * @return A SearchResponse containing the search results and total count. + */ + public SearchResponse search(UserActionSearchRequest locationCaptureSearchRequest, URLParams urlParams) { + log.info("Received request to search project task"); + + UserActionSearch locationCaptureSearch = locationCaptureSearchRequest.getUserAction(); + String idFieldName = getIdFieldName(locationCaptureSearch); + + if (isSearchByIdOnly(locationCaptureSearch, idFieldName)) { + log.info("Searching location capture by id"); + List ids = (List) ReflectionUtils.invokeMethod( + getIdMethod(Collections.singletonList(locationCaptureSearch)), + locationCaptureSearch + ); + log.info("Fetching location capture tasks with ids: {}", ids); + + // Perform search by IDs and filter results based on last changed date and tenant ID. + SearchResponse searchResponse = locationCaptureRepository.findById(ids, idFieldName); + return SearchResponse.builder() + .response(searchResponse.getResponse().stream() + .filter(lastChangedSince(urlParams.getLastChangedSince())) + .filter(havingTenantId(urlParams.getTenantId())) + .collect(Collectors.toList()) + ) + .totalCount(searchResponse.getTotalCount()) + .build(); + } + + log.info("Searching project beneficiaries using criteria"); + // Perform search based on other criteria. + return locationCaptureRepository.find(locationCaptureSearch, urlParams); + } + + /** + * Puts location capture tasks into cache. + * + * @param locationCaptures The list of location capture tasks to cache. + */ + public void putInCache(List locationCaptures) { + log.info("Putting {} location tracking tasks in cache", locationCaptures.size()); + locationCaptureRepository.putInCache(locationCaptures); + log.info("Successfully put location tracking tasks in cache"); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java index f0dd5a2645b..56e2665792a 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java @@ -1,6 +1,9 @@ package org.egov.project.service; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; import jakarta.validation.Valid; +import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestInfo; @@ -12,7 +15,9 @@ import org.egov.project.config.ProjectConfiguration; import org.egov.project.repository.ProjectRepository; import org.egov.project.service.enrichment.ProjectEnrichment; +import org.egov.project.util.ProjectServiceUtil; import org.egov.project.validator.project.ProjectValidator; +import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -24,6 +29,7 @@ @Slf4j public class ProjectService { + private final ProjectRepository projectRepository; private final ProjectValidator projectValidator; @@ -34,15 +40,21 @@ public class ProjectService { private final Producer producer; + private final ProjectServiceUtil projectServiceUtil; + + private final ObjectMapper objectMapper; + @Autowired public ProjectService( ProjectRepository projectRepository, - ProjectValidator projectValidator, ProjectEnrichment projectEnrichment, ProjectConfiguration projectConfiguration, Producer producer) { + ProjectValidator projectValidator, ProjectEnrichment projectEnrichment, ProjectConfiguration projectConfiguration, Producer producer,ProjectServiceUtil projectServiceUtil) { this.projectRepository = projectRepository; this.projectValidator = projectValidator; this.projectEnrichment = projectEnrichment; this.projectConfiguration = projectConfiguration; this.producer = producer; + this.projectServiceUtil = projectServiceUtil; + this.objectMapper = new ObjectMapper(); } public List validateProjectIds(List productIds) { @@ -100,22 +112,190 @@ public List searchProject(ProjectSearchRequest projectSearchRequest, @V return projectRepository.getProjects(projectSearchRequest.getProject(), urlParams); } - public ProjectRequest updateProject(ProjectRequest project) { - projectValidator.validateUpdateProjectRequest(project); + public ProjectRequest updateProject(ProjectRequest request) { + /* + * Validate the update project request + */ + projectValidator.validateUpdateProjectRequest(request); log.info("Update project request validated"); - //Search projects based on project ids - List projectsFromDB = searchProject(getSearchProjectRequest(project.getProjects(), project.getRequestInfo(), false), projectConfiguration.getMaxLimit(), projectConfiguration.getDefaultOffset(), project.getProjects().get(0).getTenantId(), null, false, false, false, null, null); + + /* + * Search for projects based on project IDs provided in the request + */ + List projectsFromDB = searchProject( + getSearchProjectRequest(request.getProjects(), request.getRequestInfo(), false), + projectConfiguration.getMaxLimit(), projectConfiguration.getDefaultOffset(), + request.getProjects().get(0).getTenantId(), null, false, false, false, null, null + ); log.info("Fetched projects for update request"); - //Validate Update project request against projects fetched form database - projectValidator.validateUpdateAgainstDB(project.getProjects(), projectsFromDB); - projectEnrichment.enrichProjectOnUpdate(project, projectsFromDB); - log.info("Enriched with project Number, Ids and AuditDetails"); - producer.push(projectConfiguration.getUpdateProjectTopic(), project); - log.info("Pushed to kafka"); - return project; + /* + * Validate the update project request against the projects fetched from the database + */ + projectValidator.validateUpdateAgainstDB(request.getProjects(), projectsFromDB); + + /* + * Process each project in the update request + */ + for (Project project : request.getProjects()) { + processProjectUpdate(request, project, projectsFromDB); + } + + return request; } + private void processProjectUpdate(ProjectRequest request, Project project, List projectsFromDB) { + /* + * Convert project ID to string for comparison + */ + String projectId = String.valueOf(project.getId()); + + /* + * Find the project from the database that matches the current project ID + */ + Project projectFromDB = findProjectById(projectId, projectsFromDB); + boolean isCascadingProjectDateUpdate = request.isCascadingProjectDateUpdate(); + + if (projectFromDB != null) { + /* + * Merge additional details of the project from the request and project from DB + */ + projectServiceUtil.mergeAdditionalDetails(project, projectFromDB); + + /* + * Handle cases where cascading project date update is true + */ + if (isCascadingProjectDateUpdate) { + handleUpdateProjectDates(request, project, projectFromDB); + } + /* + * Handle cases for normal update flow + */ + else { + handleNormalUpdate(request, project, projectFromDB); + } + } + } + + private Project findProjectById(String projectId, List projectsFromDB) { + /* + * Find and return the project with the matching ID from the list of projects fetched from the database + */ + return projectsFromDB.stream() + .filter(p -> projectId.equals(String.valueOf(p.getId()))) + .findFirst() + .orElse(null); + } + + + private void handleNormalUpdate(ProjectRequest request, Project project, Project projectFromDB) { + /* + * Ensure that start and end dates are not being updated when flag is false + */ + if (!project.getStartDate().equals(projectFromDB.getStartDate()) || + !project.getEndDate().equals(projectFromDB.getEndDate())) { + throw new CustomException("PROJECT_CASCADE_UPDATE_DATE_ERROR", + "Can't Update Date Range if Cascade Project Date Update false"); + } + + /* + * Enrich the project with values other than the start, end dates, and AdditionalDetails, + * and push the update to the message broker + */ + projectEnrichment.enrichProjectOnUpdate(request, project, projectFromDB); + producer.push(projectConfiguration.getUpdateProjectTopic(), request); + } + + private void handleUpdateProjectDates(ProjectRequest request, Project project, Project projectFromDB) { + /* + * Save original values of start date, end date, and additional details + */ + Long originalStartDate = projectFromDB.getStartDate(); + Long originalEndDate = projectFromDB.getEndDate(); + Object originalAdditionalDetails = projectFromDB.getAdditionalDetails(); + AuditDetails originalAuditDetails = projectFromDB.getAuditDetails(); + + + /* + * Update the project with new start date, end date, and additional details + */ + projectFromDB.setStartDate(project.getStartDate()); + projectFromDB.setEndDate(project.getEndDate()); + projectFromDB.setAdditionalDetails(project.getAdditionalDetails()); + projectFromDB.setAuditDetails(project.getAuditDetails()); + + /* + * Ensure that no other properties are being updated besides the start and end dates + */ + if (!objectMapper.valueToTree(projectFromDB).equals(objectMapper.valueToTree(project))) { + throw new CustomException( + "PROJECT_CASCADE_UPDATE_ERROR", + "Can only update Project dates and additional details if cascade Project date update true" + ); + } + + /* + * Restore original values of start date, end date, and additional details + */ + projectFromDB.setStartDate(originalStartDate); + projectFromDB.setEndDate(originalEndDate); + projectFromDB.setAdditionalDetails(originalAdditionalDetails); + projectFromDB.setAuditDetails(originalAuditDetails); + + /* + * Update lastModifiedTime and lastModifiedBy for the project + */ + projectEnrichment.enrichProjectRequestOnUpdate(project, projectFromDB, request.getRequestInfo()); + + /* + * Check and enrich cascading project dates and push the update to the message broker + */ + checkAndEnrichCascadingProjectDates(request, project); + producer.push(projectConfiguration.getUpdateProjectDateTopic(), request); + } + + + /** + * Checks and enriches cascading project dates. + * + * @param request The project request containing projects and request information. + */ + private void checkAndEnrichCascadingProjectDates(ProjectRequest request, Project project) { + /* + * Retrieve tenant ID from the first project in the request + */ + String tenantId = request.getProjects().get(0).getTenantId(); + String projectId = String.valueOf(project.getId()); + + /* + * Fetch projects from the database with ancestors and descendants + */ + List projectsFromDbWithAncestorsAndDescendants = searchProject( + getSearchProjectRequest(request.getProjects(), request.getRequestInfo(), false), + projectConfiguration.getMaxLimit(), + projectConfiguration.getDefaultOffset(), + tenantId, + null, + false, + true, + true, + null, + null + ); + + /* + * Create a map of projects from the database with ancestors and descendants + */ + Map projectFromDbWithAncestorsAndDescendantsMap = projectServiceUtil.createProjectMap(projectsFromDbWithAncestorsAndDescendants); + Project projectFromDbWithAncestorsAndDescendants = projectFromDbWithAncestorsAndDescendantsMap.get(projectId); + + /* + * Enrich project cascading dates based on the retrieved data + */ + projectEnrichment.enrichProjectCascadingDatesOnUpdate(project, projectFromDbWithAncestorsAndDescendants); + } + + /* Search for parent projects based on "parent" field and returns parent projects */ private List getParentProjects(ProjectRequest projectRequest) { List parentProjects = null; diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java index 12c8ea87062..42989bf6d57 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java @@ -34,8 +34,6 @@ import org.egov.project.validator.task.PtProductVariantIdValidator; import org.egov.project.validator.task.PtProjectBeneficiaryIdValidator; import org.egov.project.validator.task.PtProjectIdValidator; -import org.egov.project.validator.task.PtIsResouceEmptyValidator; -import org.egov.project.validator.task.PtResourceQuantityValidator; import org.egov.project.validator.task.PtRowVersionValidator; import org.egov.project.validator.task.PtUniqueEntityValidator; import org.egov.project.validator.task.PtUniqueSubEntityValidator; @@ -72,19 +70,19 @@ public class ProjectTaskService { private final ProjectConfiguration projectConfiguration; private final ProjectTaskEnrichmentService enrichmentService; - + // || validator.getClass().equals(PtResourceQuantityValidator.class) FIXME add this back once requirement confirmation is done private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PtProjectIdValidator.class) || validator.getClass().equals(PtExistentEntityValidator.class) || validator.getClass().equals(PtIsResouceEmptyValidator.class) - || validator.getClass().equals(PtResourceQuantityValidator.class) + || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class); + // || validator.getClass().equals(PtResourceQuantityValidator.class) FIXME add this back once requirement confirmation is done private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(PtProjectIdValidator.class) || validator.getClass().equals(PtIsResouceEmptyValidator.class) - || validator.getClass().equals(PtResourceQuantityValidator.class) || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class) || validator.getClass().equals(PtNullIdValidator.class) diff --git a/health-services/project/src/main/java/org/egov/project/service/UserActionService.java b/health-services/project/src/main/java/org/egov/project/service/UserActionService.java new file mode 100644 index 00000000000..0e0f76dec0e --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/UserActionService.java @@ -0,0 +1,213 @@ +package org.egov.project.service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.ds.Tuple; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.UserActionRepository; +import org.egov.project.service.enrichment.UserActionEnrichmentService; +import org.egov.project.validator.useraction.UaBoundaryValidator; +import org.egov.project.validator.useraction.UaExistentEntityValidator; +import org.egov.project.validator.useraction.UaNonExistentEntityValidator; +import org.egov.project.validator.useraction.UaNullIdValidator; +import org.egov.project.validator.useraction.UaProjectIdValidator; +import org.egov.project.validator.useraction.UaRowVersionValidator; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.project.Constants.SET_USER_ACTION; +import static org.egov.project.Constants.VALIDATION_ERROR; + +@Service +@Slf4j +public class UserActionService { + private final IdGenService idGenService; // Service for generating unique IDs + private final UserActionRepository userActionTaskRepository; // Repository for user actions + private final ServiceRequestClient serviceRequestClient; // Client for external service requests + private final ProjectConfiguration projectConfiguration; // Configuration properties for the project + private final UserActionEnrichmentService userActionEnrichmentService; // Service for enriching user actions + private final List> validators; // List of validators for user actions + + // Predicate to filter validators applicable for creation + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(UaProjectIdValidator.class) + || validator.getClass().equals(UaExistentEntityValidator.class) + || validator.getClass().equals(UaBoundaryValidator.class); + + // Predicate to filter validators applicable for updates + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(UaProjectIdValidator.class) + || validator.getClass().equals(UaNullIdValidator.class) + || validator.getClass().equals(UaNonExistentEntityValidator.class) + || validator.getClass().equals(UaRowVersionValidator.class) + || validator.getClass().equals(UaBoundaryValidator.class); + + // Constructor for dependency injection + @Autowired + public UserActionService( + IdGenService idGenService, + UserActionRepository userActionTaskRepository, + ServiceRequestClient serviceRequestClient, + ProjectConfiguration projectConfiguration, + UserActionEnrichmentService userActionEnrichmentService, + List> validators + ) { + this.idGenService = idGenService; + this.userActionTaskRepository = userActionTaskRepository; + this.serviceRequestClient = serviceRequestClient; + this.projectConfiguration = projectConfiguration; + this.userActionEnrichmentService = userActionEnrichmentService; + this.validators = validators; + } + + // Method to handle the creation of user actions + public List create(UserActionBulkRequest request, boolean isBulk) { + log.info("Received request to create bulk closed household userActions"); + + // Validate the request and get valid user actions along with error details + Tuple, Map> tuple = validate(validators, isApplicableForCreate, request, isBulk); + Map errorDetailsMap = tuple.getY(); + List validUserActions = tuple.getX(); + + try { + // If there are valid user actions, enrich and save them + if (!validUserActions.isEmpty()) { + log.info("Processing {} valid entities", validUserActions.size()); + userActionEnrichmentService.create(validUserActions, request); + userActionTaskRepository.save(validUserActions, projectConfiguration.getCreateUserActionTopic()); + log.info("Successfully created closed household userActions"); + } + } catch (Exception exception) { + // Handle and log any exceptions that occur + log.error("Error occurred while creating closed household userActions: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validUserActions, exception, SET_USER_ACTION); + } + + // Handle any validation errors + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validUserActions; + } + + // Method to handle the update of user actions + public List update(UserActionBulkRequest request, boolean isBulk) { + log.info("Received request to update bulk closed household userActions"); + + // Validate the request and get valid user actions along with error details + Tuple, Map> tuple = validate(validators, isApplicableForUpdate, request, isBulk); + Map errorDetailsMap = tuple.getY(); + List validUserActions = tuple.getX(); + + try { + // If there are valid user actions, enrich and update them + if (!validUserActions.isEmpty()) { + log.info("Processing {} valid entities", validUserActions.size()); + userActionEnrichmentService.update(validUserActions, request); + userActionTaskRepository.save(validUserActions, projectConfiguration.getUpdateUserActionTopic()); + log.info("Successfully updated bulk closed household userActions"); + } + } catch (Exception exception) { + // Handle and log any exceptions that occur + log.error("Error occurred while updating closed household userActions: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validUserActions, exception, SET_USER_ACTION); + } + + // Handle any validation errors + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validUserActions; + } + + // Method to validate user action requests + private Tuple, Map> validate(List> validators, + Predicate> applicableValidators, + UserActionBulkRequest request, boolean isBulk) { + log.info("Validating request"); + + // Validate the request using the applicable validators + Map errorDetailsMap = CommonUtils.validate(validators, + applicableValidators, request, + SET_USER_ACTION); + + // Throw exception if there are validation errors and it's not a bulk request + if (!errorDetailsMap.isEmpty() && !isBulk) { + throw new CustomException(VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + + // Filter and return valid user actions + List validUserActions = request.getUserActions().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + return new Tuple<>(validUserActions, errorDetailsMap); + } + + // Method to search for user actions based on the request and URL parameters + public SearchResponse search(UserActionSearchRequest request, URLParams urlParams) { + log.info("Received request to search project UserAction"); + + UserActionSearch userActionSearch = request.getUserAction(); + + // Determine the ID field name for search + String idFieldName = getIdFieldName(userActionSearch); + if (isSearchByIdOnly(userActionSearch, idFieldName)) { + log.info("Searching project UserAction by id"); + + // Retrieve IDs and search for user actions by ID + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(userActionSearch)), + userActionSearch); + log.info("Fetching closed household userActions with ids: {}", ids); + SearchResponse searchResponse = userActionTaskRepository.findById(ids, idFieldName); + return SearchResponse.builder().response(searchResponse.getResponse().stream() + .filter(lastChangedSince(urlParams.getLastChangedSince())) + .filter(havingTenantId(urlParams.getTenantId())) + .filter(includeDeleted(urlParams.getIncludeDeleted())) + .collect(Collectors.toList())).totalCount(searchResponse.getTotalCount()).build(); + } + + try { + // Search using the criteria specified in the request + log.info("Searching project user actions using criteria"); + return userActionTaskRepository.find(userActionSearch, urlParams); + } catch (QueryBuilderException e) { + // Handle and log query building exceptions + log.error("Error in building query: {}", ExceptionUtils.getStackTrace(e)); + throw new CustomException("ERROR_IN_QUERY", e.getMessage()); + } + } + + // Method to put user actions into cache + public void putInCache(List userActions) { + log.info("Putting {} closed household userActions in cache", userActions.size()); + userActionTaskRepository.putInCache(userActions); + log.info("Successfully put closed household userActions in cache"); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java index 6bea9a663b5..2bd670f589f 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java @@ -1,6 +1,12 @@ package org.egov.project.service.enrichment; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import digit.models.coremodels.AuditDetails; +import java.util.Map; +import java.util.ArrayList; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; @@ -9,8 +15,10 @@ import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; import org.egov.common.models.project.Target; +import org.egov.common.producer.Producer; import org.egov.common.service.IdGenService; import org.egov.project.config.ProjectConfiguration; +import org.egov.project.service.ProjectService; import org.egov.project.util.ProjectServiceUtil; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; @@ -30,6 +38,11 @@ public class ProjectEnrichment { @Autowired private ProjectServiceUtil projectServiceUtil; + @Autowired + private Producer producer; + @Autowired + private ProjectConfiguration projectConfiguration; + @Autowired private IdGenService idGenService; @@ -78,15 +91,8 @@ public void enrichProjectOnCreate(ProjectRequest request, List parentPr } /* Enrich Project on Update Request */ - public void enrichProjectOnUpdate(ProjectRequest request, List projectsFromDB) { + public void enrichProjectOnUpdate(ProjectRequest request, Project project , Project projectFromDB) { RequestInfo requestInfo = request.getRequestInfo(); - List projectsFromRequest = request.getProjects(); - - for (Project project : projectsFromRequest) { - String projectId = String.valueOf(project.getId()); - Project projectFromDB = projectsFromDB.stream().filter(p -> projectId.equals(String.valueOf(p.getId()))).findFirst().orElse(null); - - if (projectFromDB != null) { //Updating lastModifiedTime and lastModifiedBy for Project enrichProjectRequestOnUpdate(project, projectFromDB, requestInfo); log.info("Enriched project in update project request"); @@ -102,8 +108,6 @@ public void enrichProjectOnUpdate(ProjectRequest request, List projects //Add new document if id is empty or update lastModifiedTime and lastModifiedBy if id exists enrichProjectDocumentOnUpdate(project, projectFromDB, requestInfo); log.info("Enriched document in update project request"); - } - } } /* Enrich Project with id and audit details */ @@ -118,12 +122,174 @@ private void enrichProjectRequestOnCreate(Project projectRequest, RequestInfo re } /* Enrich Project update request with last modified by and last modified time */ - private void enrichProjectRequestOnUpdate(Project projectRequest, Project projectFromDB, RequestInfo requestInfo) { + public void enrichProjectRequestOnUpdate(Project projectRequest, Project projectFromDB, RequestInfo requestInfo) { projectRequest.setAuditDetails(projectFromDB.getAuditDetails()); AuditDetails auditDetails = projectServiceUtil.getAuditDetails(requestInfo.getUserInfo().getUuid(), projectFromDB.getAuditDetails(), false); projectRequest.setAuditDetails(auditDetails); log.info("Enriched project audit details for project " + projectRequest.getId()); } + public void enrichProjectCascadingDatesOnUpdate(Project project, Project projectFromDB) + { + // enrich project start and end dates along with ancestors and descendants + enrichProjectStartAndEndDateOfBothAncestorsAndDescendantsIfFoundAccordingly(project, + projectFromDB); + } + + private void enrichProjectStartAndEndDateOfBothAncestorsAndDescendantsIfFoundAccordingly( + Project projectRequest, Project projectFromDB) { + long startDate = projectRequest.getStartDate(); + long endDate = projectRequest.getEndDate(); + + /* + * Update both cycle dates and project start and end dates of descendants + */ + updateProjects(projectRequest, projectFromDB, startDate, endDate, true); + + /* + * Update both cycle dates and project start and end dates of ancestors in a way like start date = min(current, existing) + * and end date = max(current, existing) + */ + updateProjects(projectRequest, projectFromDB, startDate, endDate, false); + } + + + private void updateProjects(Project projectRequest, Project projectFromDB, long startDate, long endDate, boolean isDescendant) { + /* + * Get the list of projects from the database that are either descendants or ancestors + */ + List projectsFromDb = isDescendant ? projectFromDB.getDescendants() : projectFromDB.getAncestors(); + List modifiedProjectsFromDb = new ArrayList<>(); + + if (projectsFromDb != null) { + for (Project project : projectsFromDb) { + /* + * Update the project dates based on whether it is a descendant or ancestor + */ + updateProjectDates(project, startDate, endDate, isDescendant); + + /* + * Update the project cycles based on the request and whether it is a descendant or ancestor + */ + updateCycles(project, projectRequest, isDescendant); + + /* + * Add the modified project to the list + */ + modifiedProjectsFromDb.add(project); + } + + /* + * Push the modified projects to Kafka + */ + pushProjectsToKafka(modifiedProjectsFromDb); + } + } + + private void updateProjectDates(Project project, long startDate, long endDate, boolean isDescendant) { + if (isDescendant) { + /* + * For descendant projects, directly set the start and end dates + */ + project.setStartDate(startDate); + project.setEndDate(endDate); + } else { + /* + * For ancestor projects, set the start date to the minimum of the current and existing start dates, + * and set the end date to the maximum of the current and existing end dates + */ + project.setStartDate(Math.min(startDate, project.getStartDate())); + project.setEndDate(Math.max(endDate, project.getEndDate())); + } + } + + + private void updateCycles(Project descendantOrAncestor, Project projectRequest, boolean isDescendant) { + if (descendantOrAncestor.getAdditionalDetails() == null) { + return; + } + + ObjectMapper objectMapper = new ObjectMapper(); + + /* + * Extract additional details from descendant and request projects + */ + JsonNode descendantOrAncestorAdditionalDetails = objectMapper.valueToTree( + descendantOrAncestor.getAdditionalDetails()); + JsonNode descendantOrAncestorProjectTypeNode = descendantOrAncestorAdditionalDetails.get("projectType"); + + if (descendantOrAncestorProjectTypeNode != null) { + JsonNode descendantOrAncestorCyclesNode = descendantOrAncestorProjectTypeNode.get("cycles"); + + if (descendantOrAncestorCyclesNode != null && descendantOrAncestorCyclesNode.isArray()) { + /* + * Extract cycles from the request project + */ + JsonNode requestAdditionalDetails = objectMapper.valueToTree( + projectRequest.getAdditionalDetails()); + JsonNode requestProjectTypeNode = requestAdditionalDetails.get("projectType"); + + if (requestProjectTypeNode != null) { + JsonNode requestCyclesNode = requestProjectTypeNode.get("cycles"); + + if (requestCyclesNode != null && requestCyclesNode.isArray()) { + /* + * Iterate over descendant cycles and update as necessary + */ + for (JsonNode descendantOrAncestorCycleNode : descendantOrAncestorCyclesNode) { + String descendantOrAncestorCycleId = descendantOrAncestorCycleNode.get("id").asText(); + + for (JsonNode requestCycleNode : requestCyclesNode) { + String requestCycleId = requestCycleNode.get("id").asText(); + + if (descendantOrAncestorCycleId.equals(requestCycleId)) { + /* + * Update start and end dates of descendant cycle node + */ + long requestStartDate = requestCycleNode.get("startDate").asLong(); + long requestEndDate = requestCycleNode.get("endDate").asLong(); + long currentStartDate = descendantOrAncestorCycleNode.get("startDate").asLong(); + long currentEndDate = descendantOrAncestorCycleNode.get("endDate").asLong(); + if (isDescendant) { + ((ObjectNode) descendantOrAncestorCycleNode).put("startDate", requestStartDate); + ((ObjectNode) descendantOrAncestorCycleNode).put("endDate", requestEndDate); + } else { + ((ObjectNode) descendantOrAncestorCycleNode).put("startDate", + Math.min(requestStartDate, currentStartDate)); + ((ObjectNode) descendantOrAncestorCycleNode).put("endDate", + Math.max(requestEndDate, currentEndDate)); + } + break; // Once updated, exit the loop for this descendantCycleNode + } + } + } + + /* + * Convert updated additional details back to a map and set it on the descendant or ancestor project + */ + Map updatedAdditionalDetails = objectMapper.convertValue( + descendantOrAncestorAdditionalDetails, new TypeReference>() {}); + descendantOrAncestor.setAdditionalDetails(updatedAdditionalDetails); + } + } + } + } + } + + + private void pushProjectsToKafka(List projects) { + /* + * Create a ProjectRequest object with the list of projects + */ + ProjectRequest projectRequest = ProjectRequest.builder() + .projects(projects) + .build(); + + /* + * Push the ProjectRequest to the Kafka topic for updating projects + */ + producer.push(projectConfiguration.getUpdateProjectTopic(), projectRequest); + } + //Enrich Project with Parent Hierarchy. If parent Project hierarchy is not present then add parent locality at the beginning of project hierarchy, if present add Parent project's project hierarchy private void enrichProjectHierarchy(Project projectRequest, List parentProjects) { diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java index 9706c877ff2..db974db9be9 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java @@ -1,5 +1,9 @@ package org.egov.project.service.enrichment; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import digit.models.coremodels.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Address; @@ -11,10 +15,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.enrichForCreate; import static org.egov.common.utils.CommonUtils.enrichForUpdate; import static org.egov.common.utils.CommonUtils.enrichId; @@ -67,20 +67,24 @@ public void delete(List validTasks, TaskBulkRequest request) throws Except for (Task task : validTasks) { if (task.getIsDeleted()) { log.info("enriching all task resources for delete"); - for (TaskResource resource : task.getResources()) { - resource.setIsDeleted(true); - updateAuditDetailsForResource(request, resource); + if(!CollectionUtils.isEmpty(task.getResources())) { + for (TaskResource resource : task.getResources()) { + resource.setIsDeleted(true); + updateAuditDetailsForResource(request, resource); + } } updateAuditDetailsForTask(request, task); task.setRowVersion(task.getRowVersion() + 1); } else { int previousRowVersion = task.getRowVersion(); log.info("enriching task resources for delete"); - task.getResources().stream().filter(TaskResource::getIsDeleted).forEach(resource -> { - updateAuditDetailsForResource(request, resource); - updateAuditDetailsForTask(request, task); - task.setRowVersion(previousRowVersion + 1); - }); + if(!CollectionUtils.isEmpty(task.getResources())) { + task.getResources().stream().filter(TaskResource::getIsDeleted).forEach(resource -> { + updateAuditDetailsForResource(request, resource); + updateAuditDetailsForTask(request, task); + task.setRowVersion(previousRowVersion + 1); + }); + } } } log.info("enrichment done"); @@ -103,6 +107,7 @@ private static void updateAuditDetailsForResource(TaskBulkRequest request, TaskR private static void enrichResourcesForUpdate(TaskBulkRequest request, List tasks) { log.info("enriching resources"); for (Task task : tasks) { + if(CollectionUtils.isEmpty(task.getResources())) continue; List resourcesToCreate = task.getResources().stream() .filter(r -> r.getId() == null).collect(Collectors.toList()); List resourcesToUpdate = task.getResources().stream() diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java new file mode 100644 index 00000000000..afa331fc1cc --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java @@ -0,0 +1,67 @@ +package org.egov.project.service.enrichment; + +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.UserActionRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.project.Constants.PROJECT_USER_ACTION_ENRICHMENT_ERROR; + +@Service +@Slf4j +public class UserActionEnrichmentService { + private final IdGenService idGenService; + + private final ProjectConfiguration projectConfiguration; + + private final UserActionRepository userActionRepository; + + @Autowired + public UserActionEnrichmentService( + IdGenService idGenService, + ProjectConfiguration projectConfiguration, + UserActionRepository userActionRepository + ) { + this.idGenService = idGenService; + this.projectConfiguration = projectConfiguration; + this.userActionRepository = userActionRepository; + } + + public void create(List entities, UserActionBulkRequest request) { + log.info("starting the enrichment for create UserActions"); + log.info("generating IDs using UUID"); + try { + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching UserActions with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo(),false); + log.info("enrichment done"); + } catch (Exception exception) { + log.error("Error during enrichment for create UserActions", exception); + throw new CustomException(PROJECT_USER_ACTION_ENRICHMENT_ERROR, "Error during enrichment for create UserActions" + exception); + } + } + + public void update(List entities, UserActionBulkRequest request) { + log.info("starting the enrichment for update UserActions"); + try { + Map userActionMap = getIdToObjMap(entities); + enrichForUpdate(userActionMap, entities, request); + log.info("enrichment done"); + } catch (Exception exception) { + log.error("Error during enrichment for update UserActions", exception); + throw new CustomException(PROJECT_USER_ACTION_ENRICHMENT_ERROR, "Error during enrichment for update UserActions" + exception); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java index 74a4e2df8fa..3a0a08d31ea 100644 --- a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java @@ -92,4 +92,4 @@ public void validateBoundaryDetails(Map> locations, String } } -} +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java index 8bebbfda738..0252281f736 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import org.egov.common.models.project.TaskStatus; public class ProjectConstants { public static final String MASTER_TENANTS = "tenants"; @@ -25,33 +26,4 @@ public class ProjectConstants { public static final String OR = " OR "; - public enum TaskStatus { - BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"), - BENEFICIARY_REFERRED("BENEFICIARY_REFERRED"), - BENEFICIARY_INELIGIBLE("BENEFICIARY_INELIGIBLE"), - BENEFICIARY_SICK("BENEFICIARY_SICK"), - BENEFICIARY_ABSENT("BENEFICIARY_ABSENT"); - private String value; - - TaskStatus(String value) { - this.value = value; - } - - @Override - @JsonValue - public String toString() { - return String.valueOf(value); - } - - @JsonCreator - public static TaskStatus fromValue(String text) { - for (TaskStatus status : TaskStatus.values()) { - if (String.valueOf(status.value).equals(text)) { - return status; - } - } - return null; - } - } - } \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java b/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java index 90b2c3cfe12..7d750e8d984 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java @@ -1,10 +1,23 @@ package org.egov.project.util; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import digit.models.coremodels.AuditDetails; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.egov.common.models.project.Project; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import static java.util.Objects.isNull; @Component public class ProjectServiceUtil { + @Autowired + private ObjectMapper objectMapper; public AuditDetails getAuditDetails(String by, AuditDetails auditDetails, Boolean isCreate) { Long time = System.currentTimeMillis(); @@ -14,4 +27,53 @@ public AuditDetails getAuditDetails(String by, AuditDetails auditDetails, Boolea return AuditDetails.builder().createdBy(auditDetails.getCreatedBy()).lastModifiedBy(by) .createdTime(auditDetails.getCreatedTime()).lastModifiedTime(time).build(); } + + + /** + * Creates a map from a list of projects, using project IDs as keys. + * + * @param projects The list of projects to be converted into a map. + * @return A map with project IDs as keys and project objects as values. + */ + public Map createProjectMap(List projects) { + return projects.stream() + .collect(Collectors.toMap(p -> String.valueOf(p.getId()), Function.identity())); + } + + public void mergeAdditionalDetails( Project project , Project projectFromDb) { + project.setAdditionalDetails(jsonMerge( objectMapper.valueToTree(projectFromDb.getAdditionalDetails()), + objectMapper.valueToTree(project.getAdditionalDetails()))); + } + /** + * Method to merge additional details during update + * + * @param mainNode + * @param updateNode + * @return + */ + public JsonNode jsonMerge(JsonNode mainNode, JsonNode updateNode) { + + if (isNull(mainNode) || mainNode.isNull()) + return updateNode; + if (isNull(updateNode) || updateNode.isNull()) + return mainNode; + + Iterator fieldNames = updateNode.fieldNames(); + while (fieldNames.hasNext()) { + String fieldName = fieldNames.next(); + JsonNode jsonNode = mainNode.get(fieldName); + // if field exists and is an embedded object + if (jsonNode != null && jsonNode.isObject()) { + jsonMerge(jsonNode, updateNode.get(fieldName)); + } else { + if (mainNode instanceof ObjectNode) { + // Overwrite field + JsonNode value = updateNode.get(fieldName); + ((ObjectNode) mainNode).set(fieldName, value); + } + } + + } + return mainNode; + } } diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java index 167969d09e3..97acdc3d867 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java @@ -15,16 +15,19 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; /** - * Validator class for checking the existence of entities with the given client reference IDs. + * Validator class for checking the existence of ProjectBeneficiary entities with the given client reference IDs. * This validator checks if the provided ProjectBeneficiary entities already exist in the database based on their client reference IDs. * + * The validation ensures that each ProjectBeneficiary entity in the bulk request has a unique client reference ID, + * and if an entity with the same client reference ID already exists, an error is recorded. + * * @author kanishq-egov */ @Component @@ -38,45 +41,62 @@ public class PbExistentEntityValidator implements Validator> validate(BeneficiaryBulkRequest request) { - // Map to hold ProjectBeneficiary entities and their error details + // Initialize a map to hold ProjectBeneficiary entities and their associated error details. Map> errorDetailsMap = new HashMap<>(); - // Get the list of ProjectBeneficiary entities from the request + + // Extract the list of ProjectBeneficiary entities from the request. List entities = request.getProjectBeneficiaries(); - // Extract client reference IDs from ProjectBeneficiary entities without errors + + // Extract the client reference IDs from ProjectBeneficiary entities that do not have existing errors. List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(ProjectBeneficiary::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(ProjectBeneficiary::getClientReferenceId) // Map to extract client reference IDs. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map of client reference ID to ProjectBeneficiary entity for quick lookup. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object to query entities by client reference IDs. ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database. if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = projectBeneficiaryRepository.findById( - clientReferenceIdList, - getIdFieldName(projectBeneficiarySearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing entities with the given client reference IDs. + List existingClientReferenceIds = + projectBeneficiaryRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for the corresponding ProjectBeneficiary entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing ProjectBeneficiary entities and their associated error details. return errorDetailsMap; } diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java index c3cb60b2b8c..ba4ebc24889 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java @@ -15,15 +15,18 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; /** - * Validator class for checking the existence of entities with the given client reference IDs. - * This validator checks if the provided Task entities already exist in the database based on their client reference IDs. + * Validator class for checking the existence of ProjectTask entities with the given client reference IDs. + * This validator ensures that the Task entities provided in the bulk request do not have duplicate client reference IDs in the database. + * + * The validation checks if each Task entity's client reference ID is unique across the database, + * and if a duplicate ID is found, it adds an error to the map with the entity. * * @author: kanishq-egov */ @@ -37,46 +40,62 @@ public class PtExistentEntityValidator implements Validator> validate(TaskBulkRequest request) { - // Map to hold Task entities and their error details + // Initialize a map to store Task entities and their associated error details. Map> errorDetailsMap = new HashMap<>(); - // Get the list of Task entities from the request + + // Extract the list of Task entities from the request. List entities = request.getTasks(); - // Extract client reference IDs from Task entities without errors + + // Extract client reference IDs from Task entities that do not have existing errors. List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(Task::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(Task::getClientReferenceId) // Map to extract client reference IDs. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map for quick lookup of Task entities by client reference ID. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object to query for existing entities based on client reference IDs. TaskSearch taskSearch = TaskSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database. if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = projectTaskRepository.findById( - clientReferenceIdList, - getIdFieldName(taskSearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing entities with the given client reference IDs. + List existingClientReferenceIds = projectTaskRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding Task entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual Task entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing Task entities and their associated error details. return errorDetailsMap; } } diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java index 4487d0ae5e4..03838764dce 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java @@ -1,20 +1,22 @@ package org.egov.project.validator.task; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkRequest; import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; import org.egov.project.util.ProjectConstants; import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.project.util.ProjectConstants.TASK_NOT_ALLOWED; @@ -26,6 +28,13 @@ @Slf4j public class PtIsResouceEmptyValidator implements Validator { + private final ProjectConfiguration projectConfiguration; + + @Autowired + public PtIsResouceEmptyValidator(ProjectConfiguration projectConfiguration) { + this.projectConfiguration = projectConfiguration; + } + /** * Returns all the invalid objects in the request based on the task resources. * @param request of TaskBulkRequest class @@ -36,42 +45,20 @@ public Map> validate(TaskBulkRequest request) { List entities = request.getTasks(); if(!entities.isEmpty()) { entities.forEach(task -> { - if(CollectionUtils.isEmpty(task.getResources()) && - !(ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_REFERRED.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_SICK.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_ABSENT.toString().equals(task.getStatus()))) { + if (CollectionUtils.isEmpty(task.getResources()) && + !projectConfiguration.getNoResourceStatuses().contains(task.getStatus().toString())) { /** * If the task resource is empty or null and task status is not BENEFICIARY_REFUSED it is invalid */ + String errorMessage = ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + + String.join(ProjectConstants.OR, projectConfiguration.getNoResourceStatuses()); Error error = Error.builder() - .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + - ProjectConstants.TaskStatus.BENEFICIARY_REFUSED + - ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE + - ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_REFERRED + - ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_SICK + - ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_ABSENT) - .errorCode(TASK_NOT_ALLOWED) - .type(Error.ErrorType.NON_RECOVERABLE) - .exception(new CustomException(TASK_NOT_ALLOWED, - ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + - ProjectConstants.TaskStatus.BENEFICIARY_REFUSED + - ProjectConstants.OR + - ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE + - ProjectConstants.OR + - ProjectConstants.TaskStatus.BENEFICIARY_REFERRED + - ProjectConstants.OR + - ProjectConstants.TaskStatus.BENEFICIARY_SICK + - ProjectConstants.OR + - ProjectConstants.TaskStatus.BENEFICIARY_ABSENT)).build(); + .errorMessage(errorMessage) + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED, errorMessage)).build(); populateErrorDetails(task, error, errorDetailsMap); - } else if (!CollectionUtils.isEmpty(task.getResources()) && - (ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_REFERRED.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_SICK.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_ABSENT.toString().equals(task.getStatus()))) { + } else if (!CollectionUtils.isEmpty(task.getResources()) && projectConfiguration.getNoResourceStatuses().contains(task.getStatus().toString())) { /** * If the task resource is not empty and task status is BENEFICIARY_REFUSED */ diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java index 52b577acdbe..5a1ceaa0b3b 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java @@ -88,10 +88,10 @@ public Map> validate(TaskBulkRequest request) { }); existingEntities.forEach(task -> { - validateSubEntity(errorDetailsMap, eMap, task, + if(task.getAddress() != null) validateSubEntity(errorDetailsMap, eMap, task, Collections.singletonList(task.getAddress()), GET_ADDRESS); - validateSubEntity(errorDetailsMap, eMap, task, + if(task.getResources() != null) validateSubEntity(errorDetailsMap, eMap, task, task.getResources(), GET_RESOURCES); }); } @@ -106,10 +106,10 @@ private void validateSubEntity(Map> errorDetailsMap, String getSubEntityMethodName) { Object objFromReq = ReflectionUtils.invokeMethod(getMethod(getSubEntityMethodName, Task.class), eMap.get(entity.getId())); - List subEntitiesInReq; + List subEntitiesInReq = null; if (objFromReq instanceof List) { subEntitiesInReq = (List) objFromReq; - } else { + } else if(objFromReq != null) { // if else condition here is added to prevent creating a list of null values, and if objFromReq is null then it will bypass line 116 till end of function. subEntitiesInReq = (List) Collections.singletonList(objFromReq); } diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java index 94b2aaea221..e3be161fabb 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java @@ -26,6 +26,7 @@ import org.egov.tracer.model.CustomException; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import static org.egov.project.Constants.INTERNAL_SERVER_ERROR; import static org.egov.project.Constants.MDMS_RESPONSE; @@ -76,10 +77,12 @@ public Map> validate(TaskBulkRequest request) { List errors = new ArrayList<>(); // Extract the list of task resources List taskResources = task.getResources(); - for(TaskResource taskResource : taskResources){ - Error error = validateResourceQuantity(taskResource, request.getRequestInfo()); - if(error != null){ - errors.add(error); + if(!CollectionUtils.isEmpty(taskResources)) { + for(TaskResource taskResource : taskResources){ + Error error = validateResourceQuantity(taskResource, request.getRequestInfo()); + if(error != null){ + errors.add(error); + } } } if (!errors.isEmpty()){ diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java new file mode 100644 index 00000000000..4f0394c1556 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java @@ -0,0 +1,125 @@ +package org.egov.project.validator.useraction; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.core.Boundary; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class for validating userAction boundaries. + */ +@Component +@Order(value = 4) +@Slf4j +public class UaBoundaryValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + + private final ProjectConfiguration projectConfiguration; + + /** + * Constructor to initialize the HBoundaryValidator. + * + * @param serviceRequestClient Service request client for making HTTP requests + * @param projectConfiguration Configuration properties for the userAction module + */ + public UaBoundaryValidator(ServiceRequestClient serviceRequestClient, ProjectConfiguration projectConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.projectConfiguration = projectConfiguration; + } + + /** + * Validates the userActions' boundaries. + * + * @param request the bulk request containing userActions + * @return a map containing userActions with their corresponding list of errors + */ + @Override + public Map> validate(UserActionBulkRequest request) { + log.debug("Validating userActions boundaries."); + // Create a HashMap to store error details for each userAction + HashMap> errorDetailsMap = new HashMap<>(); + + // Filter userActions with non-null addresses + List entitiesWithValidBoundaries = request.getUserActions().parallelStream() + .filter(userAction -> Objects.nonNull(userAction.getBoundaryCode())) // Exclude null boundary codes + .collect(Collectors.toList()); + + Map> tenantIdUserActionMap = entitiesWithValidBoundaries.stream().collect(Collectors.groupingBy(UserAction::getTenantId)); + + tenantIdUserActionMap.forEach((tenantId, userActions) -> { + // Group userActions by locality code + Map> boundaryCodeUserActionsMap = userActions.stream() + .collect(Collectors.groupingBy( + userAction -> userAction.getBoundaryCode() // Group by boundary code + )); + + List boundaries = new ArrayList<>(boundaryCodeUserActionsMap.keySet()); + if(!CollectionUtils.isEmpty(boundaries)) { + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(projectConfiguration.getBoundaryServiceHost() + + projectConfiguration.getBoundarySearchUrl() + +"?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + request.getRequestInfo(), + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Filter out userActions with invalid boundary codes + List userActionsWithInvalidBoundaries = boundaryCodeUserActionsMap.entrySet().stream() + .filter(entry -> invalidBoundaryCodes.contains(entry.getKey())) // filter invalid boundary codes + .flatMap(entry -> entry.getValue().stream()) // Flatten the list of userActions + .collect(Collectors.toList()); + + // Create an error object for userActions with invalid boundaries + Error error = Error.builder() + .errorMessage("Boundary code does not exist in db") + .errorCode("PROJECT_USER_ACTION_INVALID_BOUNDARY_ERROR") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("PROJECT_USER_ACTION_INVALID_BOUNDARY_ERROR", "Boundary code does not exist in db")) + .build(); + userActionsWithInvalidBoundaries.forEach(userAction -> { + // Populate error details for the userAction + populateErrorDetails(userAction, error, errorDetailsMap); + }); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SERVICE_SEARCH_ERROR","Error in while fetching boundaries from Boundary Service : " + e.getMessage()); + } + } + }); + + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java new file mode 100644 index 00000000000..e5f3ff7a026 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java @@ -0,0 +1,99 @@ +package org.egov.project.validator.useraction; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.UserActionRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of UserAction entities based on their client reference IDs. + * This validator ensures that the UserAction entities in the bulk request do not have duplicate client reference IDs in the database. + * + * The validation checks if each UserAction entity's client reference ID already exists in the database. + * If a duplicate ID is found, it adds an error to the map with the entity. + * + * @author: kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class UaExistentEntityValidator implements Validator { + private UserActionRepository userActionRepository; + + /** + * Constructs a UaExistentEntityValidator with the specified UserActionRepository. + * + * @param userActionRepository the repository used to validate UserAction entities. + */ + @Autowired + public UaExistentEntityValidator(UserActionRepository userActionRepository) { + this.userActionRepository = userActionRepository; + } + + /** + * Validates the existence of UserAction entities in the UserActionBulkRequest. + * Checks if the provided UserAction entities already exist in the database based on their client reference IDs. + * + * @param request the bulk request containing UserAction entities. + * @return a map of UserAction entities and their associated error details. + */ + @Override + public Map> validate(UserActionBulkRequest request) { + // Map to hold UserAction entities and their error details. + log.info("Validating existence of entities in UserActionBulkRequest with {} entities", request.getUserActions().size()); + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of UserAction entities from the request. + List entities = request.getUserActions(); + + // Extract client reference IDs from UserAction entities that do not have existing errors. + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(UserAction::getClientReferenceId) // Map to extract client reference IDs. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map for quick lookup of UserAction entities by client reference ID. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object to query for existing UserAction entities based on client reference IDs. + UserActionSearch userActionSearch = UserActionSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. + .build(); + + // Check if the client reference ID list is not empty before querying the database. + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing UserAction entities with the given client reference IDs. + List existingClientReferenceIds = userActionRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.FALSE); + + // For each existing client reference ID, add an error to the map for the corresponding UserAction entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual UserAction entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing UserAction entities and their associated error details. + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java new file mode 100644 index 00000000000..c2b2534c1b0 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java @@ -0,0 +1,96 @@ +package org.egov.project.validator.useraction; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.UserActionRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.project.Constants.GET_ID; + +@Component +@Order(value = 4) +@Slf4j +public class UaNonExistentEntityValidator implements Validator { + + private final UserActionRepository userActionRepository; + + @Autowired + public UaNonExistentEntityValidator(UserActionRepository userActionRepository) { + this.userActionRepository = userActionRepository; + } + + + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("Validating existence of entities in UserActionBulkRequest with {} user actions", request.getUserActions().size()); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getUserActions(); + Class objClass = getObjClass(entities); + Method idMethod = getMethod(GET_ID, objClass); + Map eMap = getIdToObjMap(entities + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from Project UserAction entities + entities.forEach(entity -> { + idList.add(entity.getId()); + clientReferenceIdList.add(entity.getClientReferenceId()); + }); + if (!eMap.isEmpty()) { + UserActionSearch taskSearch = UserActionSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + URLParams urlParams = URLParams.builder() + .tenantId(entities.get(0).getTenantId()) + .limit(entities.size()) + .offset(0) + .includeDeleted(false) + .lastChangedSince(null) + .build(); + + List existingEntities; + try { + // Query the repository to find existing entities + existingEntities = userActionRepository.find(taskSearch, urlParams).getResponse(); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for ProjectUserAction with error: {}", e.getMessage(), e); + throw new CustomException("PROJECT_USER_ACTION_SEARCH_FAILED", "Search failed for ProjectUserAction with clientReferenceId(s): " + + clientReferenceIdList + " and id(s): " + idList + ". Error: " + e.getMessage()); + } + List nonExistentEntities = checkNonExistentEntities(eMap, + existingEntities, idMethod); + nonExistentEntities.forEach(task -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(task, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java new file mode 100644 index 00000000000..52196f57f96 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java @@ -0,0 +1,27 @@ +package org.egov.project.validator.useraction; + +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.validateForNullId; +import static org.egov.project.Constants.GET_USER_ACTION; + +@Component +@Order(value = 1) +@Slf4j +public class UaNullIdValidator implements Validator { + + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_USER_ACTION); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java new file mode 100644 index 00000000000..b7c6ea63277 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java @@ -0,0 +1,96 @@ +package org.egov.project.validator.useraction; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentRelatedEntity; + +/** + * UaProjectIdValidator is responsible for validating the Project IDs in UserActionBulkRequest. + * It checks if the Project IDs present in the UserAction entities exist in the Project repository. + */ +@Component +@Order(value = 6) +@Slf4j +public class UaProjectIdValidator implements Validator { + + private ProjectRepository projectRepository; + + @Autowired + public UaProjectIdValidator(ProjectRepository projectRepository) { + this.projectRepository = projectRepository; + } + + /** + * Validates the Project IDs in the UserActionBulkRequest. + * It checks if the Project IDs present in the UserAction entities exist in the Project repository. + * + * @param request the UserActionBulkRequest containing UserAction entities to be validated. + * @return a map of UserAction entities to a list of Errors encountered during validation. + */ + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("Starting validation of project IDs in UserActionBulkRequest with {} entities", request.getUserActions().size()); + + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getUserActions(); + + // Retrieve the class of the UserAction entities + Class objClass = getObjClass(entities); + log.debug("Retrieved UserAction entity class: {}", objClass.getName()); + + // Retrieve the method to get ProjectId from UserAction entities + Method idMethod = getMethod("getProjectId", objClass); + log.debug("Retrieved getProjectId method from UserAction entity class"); + + // Create a map of Project IDs to UserAction entities + Map eMap = getIdToObjMap(entities.stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + log.info("Created map of Project IDs to UserAction entities with {} entries", eMap.size()); + + if (!eMap.isEmpty()) { + List entityIds = new ArrayList<>(eMap.keySet()); + log.debug("List of Project IDs to validate: {}", entityIds); + + // Validate the Project IDs by checking their existence in the Project repository + List existingProjectIds = projectRepository.validateIds(entityIds, getIdFieldName(idMethod)); + log.info("Retrieved list of existing Project IDs from Project repository: {}", existingProjectIds); + + // Identify invalid UserAction entities with non-existent Project IDs + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + !existingProjectIds.contains(entity.getProjectId())).collect(Collectors.toList()); + log.info("Identified {} invalid UserAction entities with non-existent Project IDs", invalidEntities.size()); + + // Populate error details for invalid UserAction entities + invalidEntities.forEach(userAction -> { + Error error = getErrorForNonExistentRelatedEntity(userAction.getProjectId()); + populateErrorDetails(userAction, error, errorDetailsMap); + log.debug("Populated error details for UserAction with invalid Project ID: {}", userAction.getProjectId()); + }); + } else { + log.info("No Project IDs to validate as the map of Project IDs to UserAction entities is empty"); + } + + log.info("Completed validation of project IDs in UserActionBulkRequest"); + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java new file mode 100644 index 00000000000..45c8381d120 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java @@ -0,0 +1,69 @@ +package org.egov.project.validator.useraction; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.repository.UserActionRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getEntitiesWithMismatchedRowVersion; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForRowVersionMismatch; + +@Component +@Order(value = 5) +@Slf4j +public class UaRowVersionValidator implements Validator { + + private final UserActionRepository userActionRepository; + + @Autowired + public UaRowVersionValidator(UserActionRepository userActionRepository) { + this.userActionRepository = userActionRepository; + } + + + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("validating row version"); + Map> errorDetailsMap = new HashMap<>(); + try { + + Method idMethod = getIdMethod(request.getUserActions()); + Map eMap = getIdToObjMap(request.getUserActions().stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()), idMethod); + if (!eMap.isEmpty()) { + List entityIds = new ArrayList<>(eMap.keySet()); + List existingEntities = userActionRepository.findById(entityIds, + getIdFieldName(idMethod)).getResponse(); + List entitiesWithMismatchedRowVersion = + getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); + entitiesWithMismatchedRowVersion.forEach(individual -> { + Error error = getErrorForRowVersionMismatch(); + populateErrorDetails(individual, error, errorDetailsMap); + }); + } + } catch (Exception e) { + log.error("Exception occurred during validation: {}", e.getMessage()); + throw new CustomException("PROJECT_USER_ACTION_PROJECT_ID_VALIDATION_ERROR", "Error occurred while validating project IDs"+e); + } + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java new file mode 100644 index 00000000000..2214594b313 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java @@ -0,0 +1,130 @@ +package org.egov.project.web.controllers; + +import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionBulkResponse; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.service.LocationCaptureService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Controller for handling requests related to location capture tasks. + * Provides endpoints for creating and searching location capture tasks. + */ +@Controller +@RequestMapping("/user-location") +@Validated +@Slf4j +public class LocationCaptureController { + + private final HttpServletRequest httpServletRequest; + private final LocationCaptureService locationCaptureService; + private final Producer producer; + private final ProjectConfiguration projectConfiguration; + + /** + * Constructor for injecting dependencies into the LocationCaptureController. + * + * @param httpServletRequest The HttpServletRequest to capture request details. + * @param locationCaptureService The service for handling location capture logic. + * @param producer The producer for sending messages to Kafka topics. + * @param projectConfiguration Configuration properties related to the project. + */ + @Autowired + public LocationCaptureController( + HttpServletRequest httpServletRequest, + LocationCaptureService locationCaptureService, + Producer producer, + ProjectConfiguration projectConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.locationCaptureService = locationCaptureService; + this.producer = producer; + this.projectConfiguration = projectConfiguration; + } + + /** + * Endpoint for creating location capture tasks in bulk. + * Receives a UserActionBulkRequest object, processes it, and sends it to the appropriate Kafka topic. + * + * @param request The bulk request containing user actions to be created. + * @return A ResponseEntity containing the response info with HTTP status ACCEPTED. + */ + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity locationCaptureTaskV1BulkCreatePost( + @ApiParam(value = "Create Location Capture LocationCapture.", required = true) @Valid @RequestBody UserActionBulkRequest request) { + // Set the API ID in the request info using the current request URI. + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + + try { + // Send the request to the Kafka topic for bulk creation. + producer.push(projectConfiguration.getBulkCreateLocationCaptureTopic(), request); + } catch (Exception e) { + log.error("Error sending bulk create request for location captures to Kafka: {}", e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), false) + ); + } + + // Create and return a ResponseInfo object with HTTP status ACCEPTED. + return ResponseEntity.status(HttpStatus.ACCEPTED).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true) + ); + } + + /** + * Endpoint for searching location capture tasks based on given search criteria. + * Receives a UserActionSearchRequest object and returns the search results. + * + * @param urlParams URL parameters for the search. + * @param locationCaptureSearchRequest The request containing search criteria for location capture tasks. + * @return A ResponseEntity containing the search results with HTTP status OK. + * @throws Exception if there is an error during the search operation. + */ + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity locationCaptureTaskV2SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Search details of Location Capture.", required = true) @Valid @RequestBody UserActionSearchRequest locationCaptureSearchRequest + ) throws Exception { + + try { + // Perform the search using the locationCaptureService. + SearchResponse locationCaptureSearchResponse = locationCaptureService.search(locationCaptureSearchRequest, urlParams); + + // Build the response object with the search results and response info. + UserActionBulkResponse response = UserActionBulkResponse.builder() + .userActions(locationCaptureSearchResponse.getResponse()) + .totalCount(locationCaptureSearchResponse.getTotalCount()) + .responseInfo(ResponseInfoFactory.createResponseInfo(locationCaptureSearchRequest.getRequestInfo(), true)) + .build(); + + // Return the response with HTTP status OK. + return ResponseEntity.status(HttpStatus.OK).body(response); + } catch (Exception e) { + log.error("Error occurred during search operation for location captures: {}", e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + UserActionBulkResponse.builder() + .responseInfo(ResponseInfoFactory.createResponseInfo(locationCaptureSearchRequest.getRequestInfo(), false)) + .build() + ); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java new file mode 100644 index 00000000000..34a56ae9ca5 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java @@ -0,0 +1,162 @@ +package org.egov.project.web.controllers; + +import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionBulkResponse; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.service.UserActionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Controller for handling user action-related requests. + * Provides endpoints for creating, updating, and searching user actions. + */ +@Controller +@RequestMapping("/user-action") +@Validated +@Slf4j +public class UserActionController { + + private final HttpServletRequest httpServletRequest; + private final UserActionService userActionService; + private final Producer producer; + private final ProjectConfiguration projectConfiguration; + + /** + * Constructor for injecting dependencies into the UserActionController. + * + * @param httpServletRequest The HttpServletRequest to capture request details. + * @param userActionService The service for handling user action logic. + * @param producer The producer for sending messages to Kafka topics. + * @param projectConfiguration Configuration properties related to the project. + */ + @Autowired + public UserActionController( + HttpServletRequest httpServletRequest, + UserActionService userActionService, + Producer producer, + ProjectConfiguration projectConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.userActionService = userActionService; + this.producer = producer; + this.projectConfiguration = projectConfiguration; + } + + /** + * Endpoint for creating user actions in bulk. + * Receives a UserActionBulkRequest object, processes it, and sends it to the appropriate Kafka topic. + * + * @param request The bulk request containing user actions to be created. + * @return A ResponseEntity containing the response info with HTTP status ACCEPTED. + */ + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity userActionV1BulkCreatePost( + @ApiParam(value = "Capture linkage of Project and User Action UserAction.", required = true) @Valid @RequestBody UserActionBulkRequest request + ) { + // Set the API ID in the request info using the current request URI. + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + + try { + log.debug("Pushing user action bulk create request to Kafka topic: {}", projectConfiguration.getBulkCreateUserActionTopic()); + // Send the request to the Kafka topic for bulk creation. + producer.push(projectConfiguration.getBulkCreateUserActionTopic(), request); + log.info("Successfully pushed user action bulk create request to Kafka"); + } catch (Exception e) { + log.error("Failed to push user action bulk create request to Kafka", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), false) + ); + } + + // Create and return a ResponseInfo object with HTTP status ACCEPTED. + return ResponseEntity.status(HttpStatus.ACCEPTED).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true) + ); + } + + /** + * Endpoint for searching user actions based on given search criteria. + * Receives a UserActionSearchRequest object and returns the search results. + * + * @param urlParams URL parameters for the search. + * @param request The request containing search criteria for user actions. + * @return A ResponseEntity containing the search results with HTTP status OK. + */ + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity userActionV2SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Project User Action UserAction.", required = true) @Valid @RequestBody UserActionSearchRequest request + ) { + log.debug("Executing search with URLParams: {} and request: {}", urlParams, request); + + // Perform the search using the userActionService. + SearchResponse userActions; + try { + // Perform the search using the userActionService. + userActions = userActionService.search(request, urlParams); + log.info("Successfully searched for user actions: {}", userActions.getResponse().size()); + } catch (Exception e) { + log.error("Failed to search for user actions", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + + // Build the response object with the search results and response info. + UserActionBulkResponse response = UserActionBulkResponse.builder() + .userActions(userActions.getResponse()) + .totalCount(userActions.getTotalCount()) + .responseInfo(ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true)) + .build(); + + // Return the response with HTTP status OK. + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * Endpoint for updating user actions in bulk. + * Receives a UserActionBulkRequest object, processes it, and sends it to the appropriate Kafka topic. + * + * @param request The bulk request containing user actions to be updated. + * @return A ResponseEntity containing the response info with HTTP status ACCEPTED. + */ + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity userActionV1BulkUpdatePost( + @ApiParam(value = "Capture linkage of Project and User Action UserAction.", required = true) @Valid @RequestBody UserActionBulkRequest request + ) { + // Set the API ID in the request info using the current request URI. + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + + try { + // Send the request to the Kafka topic for bulk update. + producer.push(projectConfiguration.getBulkUpdateUserActionTopic(), request); + } catch (Exception e) { + log.error("Failed to push user action bulk update request to Kafka", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), false) + ); + } + + // Create and return a ResponseInfo object with HTTP status ACCEPTED. + return ResponseEntity.status(HttpStatus.ACCEPTED).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true) + ); + } +} diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index f52ba8f6584..93f601466a9 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -144,6 +144,7 @@ project.search.max.limit=200 project.management.system.kafka.create.topic=save-project project.management.system.kafka.update.topic=update-project +project.management.system.kafka.update.date.topic=update-project-date # BOUNDARY SERVICE egov.boundary.host=http://localhost:8081 @@ -168,3 +169,15 @@ egov.location.hierarchy.type=ADMIN #---------Attendance-----------# project.staff.attendance.topic=project-staff-attendance-health-topic +#-------Closed Household Task-------# +project.user.action.kafka.create.topic=save-user-action-project-topic +project.user.action.kafka.update.topic=update-user-action-project-topic +project.user.action.consumer.bulk.create.topic=save-user-action-project-bulk-topic +project.user.action.consumer.bulk.update.topic=update-user-action-project-bulk-topic + +#-------Location Capture Task-------# +project.location.capture.kafka.create.topic=save-location-capture-project-topic +project.location.capture.consumer.bulk.create.topic=save-location-capture-project-bulk-topic + +#---------No resource statuses ------------# +project.task.no.resource.validation.status=ADMINISTRATION_FAILED, BENEFICIARY_REFUSED, CLOSED_HOUSEHOLD, NOT_ADMINISTERED \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql new file mode 100644 index 00000000000..fd9a0f8f611 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql @@ -0,0 +1,23 @@ +CREATE TABLE IF NOT EXISTS USER_LOCATION ( + id CHARACTER VARYING(64), + clientReferenceId CHARACTER VARYING(64), + tenantId CHARACTER VARYING(1000) NOT NULL, + projectId CHARACTER VARYING(64) NOT NULL, + latitude DOUBLE PRECISION NOT NULL, + longitude DOUBLE PRECISION NOT NULL, + locationAccuracy INTEGER NOT NULL, + boundaryCode CHARACTER VARYING(256) NOT NULL, + action CHARACTER VARYING(256), + createdBy CHARACTER VARYING(64) NOT NULL, + createdTime BIGINT NOT NULL, + lastModifiedBy CHARACTER VARYING(64) NOT NULL, + lastModifiedTime BIGINT NOT NULL, + clientCreatedTime BIGINT, + clientLastModifiedTime BIGINT, + clientCreatedBy CHARACTER VARYING(64), + clientLastModifiedBy CHARACTER VARYING(64), + additionalDetails jsonb, + CONSTRAINT pk_user_location PRIMARY KEY (id) +); + +CREATE INDEX IF NOT EXISTS idx_user_location_clientCreatedBy ON USER_LOCATION (clientCreatedBy); diff --git a/health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql new file mode 100644 index 00000000000..411e86e86ef --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql @@ -0,0 +1,28 @@ +CREATE TABLE IF NOT EXISTS USER_ACTION ( +id character varying(64), +clientReferenceId character varying(64), +tenantId character varying(1000) not null, +projectId character varying(64) not null, +latitude double precision not null, +longitude double precision not null, +locationAccuracy INTEGER not null, +boundaryCode CHARACTER VARYING(256) not null, +action CHARACTER VARYING(256) not null, +beneficiaryTag CHARACTER VARYING(64), +resourceTag CHARACTER VARYING(64), +status character varying(1000), +additionalDetails jsonb, +createdBy character varying(64) not null, +createdTime bigint not null, +lastModifiedBy character varying(64) not null, +lastModifiedTime bigint not null, +clientCreatedTime bigint, +clientLastModifiedTime bigint, +clientCreatedBy character varying(64), +clientLastModifiedBy character varying(64), +rowVersion bigint, + CONSTRAINT pk_user_action_id PRIMARY KEY (id), + CONSTRAINT uk_user_action_clientReference_id UNIQUE (clientReferenceId) +); + +CREATE INDEX IF NOT EXISTS idx_user_action_projectId_clientCreatedBy ON USER_ACTION (projectId, clientCreatedBy); diff --git a/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java index ddda5a11de5..453e3be4d11 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java @@ -1,10 +1,11 @@ package org.egov.project.helper; +import java.util.Arrays; + import org.egov.common.helper.AuditDetailsTestBuilder; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskResource; - -import java.util.Arrays; +import org.egov.common.models.project.TaskStatus; public class TaskTestBuilder { @@ -31,7 +32,8 @@ public TaskTestBuilder withTask() { TaskResource.builder().tenantId("default").isDelivered(false) .quantity(100.0).productVariantId("v101").build())) .projectId("some-id").createdBy("some-id") - .createdDate(100L).status("status") + .createdDate(100L) + .status(TaskStatus.DELIVERED) .isDeleted(false).projectBeneficiaryId("some-id") .rowVersion(0) .hasErrors(Boolean.FALSE) diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md index c605b868638..21e78657688 100644 --- a/health-services/referralmanagement/CHANGELOG.md +++ b/health-services/referralmanagement/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog All notable changes to this module will be documented in this file. +## 1.0.3 - 2024-08-09 +- Upgraded downsync logic. + + ## 1.0.2 - 2024-05-29 - Upgraded to Core 2.9LTS - Client reference ID validation added diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index 915072c78a1..b9d85ad8269 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -6,7 +6,7 @@ referralmanagement jar referralmanagement - 1.0.2 + 1.0.3 17 ${java.version} @@ -46,7 +46,7 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java index f33a82c8bea..b24119eb8dd 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java @@ -1,6 +1,7 @@ package org.egov.referralmanagement; public interface Constants { + String SET_SIDE_EFFECTS = "setSideEffects"; String GET_SIDE_EFFECTS = "getSideEffects"; String SET_REFERRALS = "setReferrals"; @@ -15,5 +16,10 @@ public interface Constants { String STAFF = "STAFF"; String FACILITY = "FACILITY"; + public static final String HCM_MASTER_PROJECTTYPE = "projectTypes"; + public static final String HCM_MDMS_PROJECT_MODULE_NAME = "HCM-PROJECT-TYPES"; + public static final String HCM_PROJECT_TYPE_FILTER_CODE = "$.[?(@.code=='%s')]"; + public static final String HCM_MDMS_PROJECTTYPE_RES_PATH = "$.MdmsRes." + HCM_MDMS_PROJECT_MODULE_NAME + "." + HCM_MASTER_PROJECTTYPE + ".*"; + String INVALID_RECIPIENT_TYPE = "Invalid Recipient Type"; } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java index 1113ac58efb..e69325f19c5 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -109,4 +109,10 @@ public class ReferralManagementConfiguration { @Value("${egov.search.individual.url}") private String individualSearchUrl; + @Value("${egov.mdms.host}") + private String mdmsHost; + + @Value("${egov.mdms.search.endpoint}") + private String mdmsSearchUrl; + } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java index f3ca4fa075d..7db34924dd4 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java @@ -3,11 +3,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.household.Household; @@ -46,6 +48,7 @@ import org.springframework.util.CollectionUtils; @Service +@Slf4j public class DownsyncService { private ServiceRequestClient restClient; @@ -58,28 +61,34 @@ public class DownsyncService { private ReferralManagementService referralService; + private MasterDataService masterDataService; + @Autowired - public DownsyncService(ServiceRequestClient serviceRequestClient, - ReferralManagementConfiguration referralManagementConfiguration, - NamedParameterJdbcTemplate jdbcTemplate, - SideEffectService sideEffectService, - ReferralManagementService referralService) { + public DownsyncService( ServiceRequestClient serviceRequestClient, + ReferralManagementConfiguration referralManagementConfiguration, + NamedParameterJdbcTemplate jdbcTemplate, + SideEffectService sideEffectService, + ReferralManagementService referralService, + MasterDataService masterDataService ) { this.restClient = serviceRequestClient; this.configs = referralManagementConfiguration; this.jdbcTemplate = jdbcTemplate; - this.sideEffectService = sideEffectService; - this.referralService = referralService; + this.sideEffectService=sideEffectService; + this.referralService=referralService; + this.masterDataService=masterDataService; } /** + * * @param downsyncRequest * @return Downsync */ public Downsync prepareDownsyncData(DownsyncRequest downsyncRequest) { Downsync downsync = new Downsync(); + DownsyncCriteria downsyncCriteria = downsyncRequest.getDownsyncCriteria(); List householdIds = null; Set individualIds = null; @@ -87,43 +96,60 @@ public Downsync prepareDownsyncData(DownsyncRequest downsyncRequest) { List beneficiaryClientRefIds = null; List taskClientRefIds = null; - downsync.setDownsyncCriteria(downsyncRequest.getDownsyncCriteria()); + + downsync.setDownsyncCriteria(downsyncCriteria); + boolean isSyncTimeAvailable = null != downsyncCriteria.getLastSyncedTime(); + + //Project project = getProjectType(downsyncRequest); + LinkedHashMap projectType = masterDataService.getProjectType(downsyncRequest); + /* search household */ householdIds = searchHouseholds(downsyncRequest, downsync); - if (!CollectionUtils.isEmpty(householdIds)) - /* search household member using household ids */ + /* search household member using household ids */ + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(householdIds)) { individualIds = searchMembers(downsyncRequest, downsync, householdIds); + } - if (!CollectionUtils.isEmpty(individualIds)) { - - /* search individuals using individual ids */ + /* search individuals using individual ids */ + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(individualIds) ) { individualClientRefIds = searchIndividuals(downsyncRequest, downsync, individualIds); } - if (!CollectionUtils.isEmpty(individualClientRefIds)) { - /* search beneficiary using individual ids */ - beneficiaryClientRefIds = searchBeneficiaries(downsyncRequest, downsync, individualClientRefIds); + /* search beneficiary using individual ids OR household ids */ + + String beneficiaryType = (String) projectType.get("beneficiaryType"); + + beneficiaryClientRefIds = individualClientRefIds; + + if("HOUSEHOLD".equalsIgnoreCase(beneficiaryType)) + beneficiaryClientRefIds = downsync.getHouseholds().stream().map(Household::getClientReferenceId).collect(Collectors.toList()); + + //fetch beneficiary in the db + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + beneficiaryClientRefIds = searchBeneficiaries(downsyncRequest, downsync, beneficiaryClientRefIds); } - if (!CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + /* search tasks using beneficiary uuids */ + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(beneficiaryClientRefIds)) { - /* search tasks using beneficiary uuids */ - taskClientRefIds = searchTasks(downsyncRequest, downsync, beneficiaryClientRefIds); + taskClientRefIds = searchTasks(downsyncRequest, downsync, beneficiaryClientRefIds, projectType); /* ref search */ referralSearch(downsyncRequest, downsync, beneficiaryClientRefIds); } - if (!CollectionUtils.isEmpty(taskClientRefIds)) { + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(taskClientRefIds)) { searchSideEffect(downsyncRequest, downsync, taskClientRefIds); } return downsync; } + /** + * * @param downsyncRequest * @param downsync * @return @@ -135,7 +161,7 @@ private List searchHouseholds(DownsyncRequest downsyncRequest, Downsync StringBuilder householdUrl = new StringBuilder(configs.getHouseholdHost()) .append(configs.getHouseholdSearchUrl()); - householdUrl = appendUrlParams(householdUrl, criteria, null, null); + householdUrl = appendUrlParams(householdUrl, criteria, null, null, true); HouseholdSearch householdSearch = HouseholdSearch.builder() .localityCode(criteria.getLocality()) @@ -151,13 +177,14 @@ private List searchHouseholds(DownsyncRequest downsyncRequest, Downsync downsync.setHouseholds(households); downsync.getDownsyncCriteria().setTotalCount(res.getTotalCount()); - if (CollectionUtils.isEmpty(households)) + if(CollectionUtils.isEmpty(households)) return Collections.emptyList(); return households.stream().map(Household::getId).collect(Collectors.toList()); } /** + * * @param downsyncRequest * @param downsync * @param individualIds @@ -171,12 +198,15 @@ private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync StringBuilder url = new StringBuilder(configs.getIndividualHost()) .append(configs.getIndividualSearchUrl()); - url = appendUrlParams(url, criteria, 0, individualIds.size()); + + url = appendUrlParams(url, criteria, 0, individualIds.size(),true); IndividualSearch individualSearch = IndividualSearch.builder() - .id(new ArrayList<>(individualIds)) .build(); + if(!CollectionUtils.isEmpty(individualIds)) + individualSearch.setId(new ArrayList<>(individualIds)); + IndividualSearchRequest searchRequest = IndividualSearchRequest.builder() .individual(individualSearch) .requestInfo(requestInfo) @@ -189,6 +219,7 @@ private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync } /** + * * @param downsyncRequest * @param householdIds * @return @@ -196,21 +227,17 @@ private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync private Set searchMembers(DownsyncRequest downsyncRequest, Downsync downsync, List householdIds) { - StringBuilder memberUrl = new StringBuilder(configs.getHouseholdHost()) - .append(configs.getHouseholdMemberSearchUrl()); + Long lastChangedSince = downsyncRequest.getDownsyncCriteria().getLastSyncedTime(); - String memberIdsquery = "SELECT id from HOUSEHOLD_MEMBER where householdId IN (:householdIds)"; - - Map paramMap = new HashMap<>(); - paramMap.put("householdIds", householdIds); - appendUrlParams(memberUrl, downsyncRequest.getDownsyncCriteria(), 0, householdIds.size()); - - /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of household ids*/ - List memberids = jdbcTemplate.queryForList(memberIdsquery, paramMap, String.class); + List memberids = getPrimaryIds(householdIds, "householdId","HOUSEHOLD_MEMBER",lastChangedSince); if (CollectionUtils.isEmpty(memberids)) return Collections.emptySet(); + StringBuilder memberUrl = new StringBuilder(configs.getHouseholdHost()) + .append(configs.getHouseholdMemberSearchUrl()); + + appendUrlParams(memberUrl, downsyncRequest.getDownsyncCriteria(), 0, householdIds.size(), false); HouseholdMemberSearch memberSearch = HouseholdMemberSearch.builder() .id(memberids) @@ -228,92 +255,94 @@ private Set searchMembers(DownsyncRequest downsyncRequest, Downsync down } /** + * * @param downsyncRequest * @param downsync - * @param individualClientRefIds + * @param beneficiaryClientRefIds * @return clientreferenceid of beneficiary object */ private List searchBeneficiaries(DownsyncRequest downsyncRequest, Downsync downsync, - List individualClientRefIds) { + List beneficiaryClientRefIds) { DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + Long lastChangedSince =criteria.getLastSyncedTime(); + + List beneficiaryIds = getPrimaryIds( + beneficiaryClientRefIds, + "beneficiaryclientreferenceid", + "PROJECT_BENEFICIARY", + lastChangedSince + ); + + if(CollectionUtils.isEmpty(beneficiaryIds)) + return Collections.emptyList(); + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectBeneficiarySearchUrl()); + + url = appendUrlParams(url, criteria, 0, beneficiaryClientRefIds.size(),false); + + ProjectBeneficiarySearch search = ProjectBeneficiarySearch.builder() + .id(beneficiaryIds) + .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) + .build(); + + BeneficiarySearchRequest searchRequest = BeneficiarySearchRequest.builder() + .projectBeneficiary(search) + .requestInfo(requestInfo) + .build(); + + List beneficiaries = restClient.fetchResult(url, searchRequest, BeneficiaryBulkResponse.class).getProjectBeneficiaries(); + downsync.setProjectBeneficiaries(beneficiaries); + + return beneficiaries.stream().map(ProjectBeneficiary::getClientReferenceId).collect(Collectors.toList()); + } + - StringBuilder url = new StringBuilder(configs.getProjectHost()) - .append(configs.getProjectBeneficiarySearchUrl()); - url = appendUrlParams(url, criteria, 0, individualClientRefIds.size()); - - String beneficiaryIdQuery = "SELECT id from PROJECT_BENEFICIARY where beneficiaryclientreferenceid IN (:beneficiaryIds)"; - - Map paramMap = new HashMap<>(); - paramMap.put("beneficiaryIds", individualClientRefIds); - - /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of beneficiary ids*/ - List ids = jdbcTemplate.queryForList(beneficiaryIdQuery, paramMap, String.class); - - if(CollectionUtils.isEmpty(ids)) - return Collections.emptyList(); - - ProjectBeneficiarySearch search = ProjectBeneficiarySearch.builder() - .id(ids) - .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) - .build(); - - BeneficiarySearchRequest searchRequest = BeneficiarySearchRequest.builder() - .projectBeneficiary(search) - .requestInfo(requestInfo) - .build(); - - List beneficiaries = restClient.fetchResult(url, searchRequest, BeneficiaryBulkResponse.class).getProjectBeneficiaries(); - downsync.setProjectBeneficiaries(beneficiaries); - - return beneficiaries.stream().map(ProjectBeneficiary::getClientReferenceId).collect(Collectors.toList()); - } /** + * * @param downsyncRequest * @param downsync * @param beneficiaryClientRefIds + * @param projectType * @return */ private List searchTasks(DownsyncRequest downsyncRequest, Downsync downsync, - List beneficiaryClientRefIds) { - - DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); - RequestInfo requestInfo = downsyncRequest.getRequestInfo(); - - StringBuilder url = new StringBuilder(configs.getProjectHost()) - .append(configs.getProjectTaskSearchUrl()); - - String taskIdQuery = "SELECT id from PROJECT_TASK where projectBeneficiaryClientReferenceId IN (:beneficiaryClientRefIds)"; - - Map paramMap = new HashMap<>(); - paramMap.put("beneficiaryClientRefIds", beneficiaryClientRefIds); - - /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ - List taskIds = jdbcTemplate.queryForList(taskIdQuery, paramMap, String.class); - url = appendUrlParams(url, criteria, 0, taskIds.size()); - - if(CollectionUtils.isEmpty(taskIds)) - return Collections.emptyList(); - - TaskSearch search = TaskSearch.builder() - .id(taskIds) - .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) - .build(); - - TaskSearchRequest searchRequest = TaskSearchRequest.builder() - .task(search) - .requestInfo(requestInfo) - .build(); - - List tasks = restClient.fetchResult(url, searchRequest, TaskBulkResponse.class).getTasks(); - downsync.setTasks(tasks); - - return tasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); - } + List beneficiaryClientRefIds, LinkedHashMap projectType) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + List taskIds = getPrimaryIds(beneficiaryClientRefIds, "projectBeneficiaryClientReferenceId", "PROJECT_TASK", + criteria.getLastSyncedTime()); + + if(CollectionUtils.isEmpty(taskIds)) + return Collections.emptyList(); + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectTaskSearchUrl()); + + url = appendUrlParams(url, criteria, 0, taskIds.size(), false); + + TaskSearch search = TaskSearch.builder() + .id(taskIds) + .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) + .build(); + + TaskSearchRequest searchRequest = TaskSearchRequest.builder() + .task(search) + .requestInfo(requestInfo) + .build(); + + List tasks = restClient.fetchResult(url, searchRequest, TaskBulkResponse.class).getTasks(); + downsync.setTasks(tasks); + + return tasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); + } /** + * * @param downsyncRequest * @param downsync * @param taskClientRefIds @@ -324,33 +353,29 @@ private void searchSideEffect(DownsyncRequest downsyncRequest, Downsync downsync DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); RequestInfo requestInfo = downsyncRequest.getRequestInfo(); - // search side effect FIXME - tasks id array search not available - String sEIdQuery = "SELECT id from SIDE_EFFECT where taskClientReferenceId IN (:taskClientRefIds)"; - - Map paramMap = new HashMap<>(); - paramMap.put("taskClientRefIds", taskClientRefIds); - /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ - List SEIds = jdbcTemplate.queryForList(sEIdQuery, paramMap, String.class); + List SEIds = getPrimaryIds(taskClientRefIds, "taskClientReferenceId", "SIDE_EFFECT", criteria.getLastSyncedTime()); - if (CollectionUtils.isEmpty(SEIds)) + if(CollectionUtils.isEmpty(SEIds)) return; SideEffectSearch search = SideEffectSearch.builder() .id(SEIds) .build(); + SideEffectSearchRequest effectSearchRequest = SideEffectSearchRequest.builder() .sideEffect(search) .requestInfo(requestInfo) .build(); List effects = sideEffectService.search( - effectSearchRequest, - SEIds.size(), - 0, - criteria.getTenantId(), - criteria.getLastSyncedTime(), - criteria.getIncludeDeleted()).getResponse(); + effectSearchRequest, + SEIds.size(), + 0, + criteria.getTenantId(), + criteria.getLastSyncedTime(), + criteria.getIncludeDeleted() + ).getResponse(); downsync.setSideEffects(effects); } @@ -360,28 +385,72 @@ private void referralSearch(DownsyncRequest downsyncRequest, Downsync downsync, DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + Integer limit = beneficiaryClientRefIds.size(); ReferralSearch search = ReferralSearch.builder() - .projectBeneficiaryClientReferenceId(beneficiaryClientRefIds) .build(); + if(!CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + search.setProjectBeneficiaryClientReferenceId(beneficiaryClientRefIds); + limit = null; + } + ReferralSearchRequest searchRequest = ReferralSearchRequest.builder() .referral(search) .requestInfo(requestInfo) .build(); List referrals = referralService.search( - searchRequest, - beneficiaryClientRefIds.size(), - 0, - criteria.getTenantId(), - criteria.getLastSyncedTime(), - criteria.getIncludeDeleted()).getResponse(); + searchRequest, + limit, + 0, + criteria.getTenantId(), + criteria.getLastSyncedTime(), + criteria.getIncludeDeleted() + ).getResponse(); downsync.setReferrals(referrals); } + /** + * common method to fetch Ids with list of relation Ids like id of member with householdIds + * @param idList + * @param idListFieldName + * @param tableName + * @param lastChangedSince + * @return + */ + private List getPrimaryIds(List idList, String idListFieldName, String tableName, Long lastChangedSince) { + + /** + * Adding lastShangedSince to id query to avoid load on API search for members + */ + boolean isAndRequired = false; + Map paramMap = new HashMap<>(); + StringBuilder memberIdsquery = new StringBuilder("SELECT id from %s WHERE "); + + + if (!CollectionUtils.isEmpty(idList)) { + + memberIdsquery.append("%s IN (:%s)"); + paramMap.put(idListFieldName, idList); + isAndRequired = true; + } + + if (null != lastChangedSince) { + if(isAndRequired) + memberIdsquery.append(" AND "); + memberIdsquery.append(" lastModifiedTime >= (:lastChangedSince)"); + paramMap.put("lastChangedSince", lastChangedSince); + } + + String finalQuery = String.format(memberIdsquery.toString(), tableName, idListFieldName, idListFieldName); + /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of household ids*/ + List memberids = jdbcTemplate.queryForList(finalQuery, paramMap, String.class); + return memberids; + } + /** * append url params * @@ -389,9 +458,10 @@ private void referralSearch(DownsyncRequest downsyncRequest, Downsync downsync, * @param criteria * @param offset * @param limit + * @param sendPrevSyncTime * @return */ - private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criteria, Integer offset, Integer limit) { + private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criteria, Integer offset, Integer limit, boolean sendPrevSyncTime) { url.append("?tenantId=") .append(criteria.getTenantId()) @@ -399,18 +469,21 @@ private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criter .append(criteria.getIncludeDeleted()) .append("&limit="); - if (null != limit) + if (null != limit && limit != 0) url.append(limit); else url.append(criteria.getLimit()); url.append("&offset="); - if (null != offset) + if(null != offset) url.append(offset); else url.append(criteria.getOffset()); + if(sendPrevSyncTime && null != criteria.getLastSyncedTime()) + url.append("&lastChangedSince=").append(criteria.getLastSyncedTime()); + return url; } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java new file mode 100644 index 00000000000..3c09df3edde --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java @@ -0,0 +1,129 @@ +package org.egov.referralmanagement.service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import com.jayway.jsonpath.JsonPath; +import digit.models.coremodels.mdms.MasterDetail; +import digit.models.coremodels.mdms.MdmsCriteria; +import digit.models.coremodels.mdms.MdmsCriteriaReq; +import digit.models.coremodels.mdms.ModuleDetail; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.project.Project; +import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectResponse; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncCriteria; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import static org.egov.referralmanagement.Constants.HCM_MASTER_PROJECTTYPE; +import static org.egov.referralmanagement.Constants.HCM_MDMS_PROJECTTYPE_RES_PATH; +import static org.egov.referralmanagement.Constants.HCM_MDMS_PROJECT_MODULE_NAME; +import static org.egov.referralmanagement.Constants.HCM_PROJECT_TYPE_FILTER_CODE; + +@Slf4j +@Service +public class MasterDataService { + + private ServiceRequestClient restClient; + + private ReferralManagementConfiguration configs; + + @Autowired + public MasterDataService(ServiceRequestClient serviceRequestClient, + ReferralManagementConfiguration referralManagementConfiguration) { + + this.restClient = serviceRequestClient; + this.configs = referralManagementConfiguration; + + } + + + @SuppressWarnings("unchecked") + public LinkedHashMap getProjectType(DownsyncRequest downsyncRequest) { + + DownsyncCriteria downsyncCriteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo info = downsyncRequest.getRequestInfo(); + String projectId = downsyncCriteria.getProjectId(); + + + Project project = getProject(downsyncCriteria, info, projectId); + + String projectCode = project.getProjectType(); // FIXME + + /* + * TODO FIXME code should get upgraded when next version of project is created with execution plan (project type master) in the additional details + */ + StringBuilder mdmsUrl = new StringBuilder(configs.getMdmsHost()) + .append(configs.getMdmsSearchUrl()); + + /* + * Assumption is that the project code is always unique + */ + MasterDetail masterDetail = MasterDetail.builder() + .name(HCM_MASTER_PROJECTTYPE) + .filter(String.format(HCM_PROJECT_TYPE_FILTER_CODE, projectCode)) // projectCode FIXME + .build(); + + ModuleDetail moduleDetail = ModuleDetail.builder() + .masterDetails(Arrays.asList(masterDetail)) + .moduleName(HCM_MDMS_PROJECT_MODULE_NAME) + .build(); + + MdmsCriteria mdmsCriteria = MdmsCriteria.builder() + .moduleDetails(Arrays.asList(moduleDetail)) + .tenantId(downsyncCriteria.getTenantId().split("//.")[0]) + .build(); + + MdmsCriteriaReq mdmsCriteriaReq = MdmsCriteriaReq.builder() + .mdmsCriteria(mdmsCriteria) + .requestInfo(info) + .build(); + + Map mdmsRes = restClient.fetchResult(mdmsUrl, mdmsCriteriaReq, HashMap.class); + List projectTypeRes = null; + try { + projectTypeRes = JsonPath.read(mdmsRes, HCM_MDMS_PROJECTTYPE_RES_PATH); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException("JSONPATH_ERROR", "Failed to parse mdms response"); + } + + return (LinkedHashMap) projectTypeRes.get(0); + + } + + + private Project getProject(DownsyncCriteria downsyncCriteria, RequestInfo info, String projectId) { + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectSearchUrl()) + .append("?offset=0") + .append("&limit=100") + .append("&tenantId=").append(downsyncCriteria.getTenantId()); + + Project project = Project.builder() + .id(projectId) + .tenantId(downsyncCriteria.getTenantId()) + .build(); + + ProjectRequest projectRequest = ProjectRequest.builder() + .projects(Arrays.asList(project)) + .requestInfo(info) + .build(); + + ProjectResponse res = restClient.fetchResult(url, projectRequest, ProjectResponse.class); + return res.getProject().get(0); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index b14512d7551..38973d34e3c 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -66,8 +66,7 @@ public class ReferralManagementService { || validator.getClass().equals(RmExistentEntityValidator.class) || validator.getClass().equals(RmReferrerIdValidator.class) || validator.getClass().equals(RmRecipientIdValidator.class) - || validator.getClass().equals(RmSideEffectIdValidator.class) - || validator.getClass().equals(RmRowVersionValidator.class); + || validator.getClass().equals(RmSideEffectIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(RmProjectBeneficiaryIdValidator.class) @@ -82,7 +81,8 @@ public class ReferralManagementService { private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(RmNullIdValidator.class) - || validator.getClass().equals(RmNonExistentEntityValidator.class); + || validator.getClass().equals(RmNonExistentEntityValidator.class) + || validator.getClass().equals(RmRowVersionValidator.class); public ReferralManagementService(IdGenService idGenService, ReferralRepository referralRepository, ReferralManagementConfiguration referralManagementConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java index 8725344af7d..c12c03054ef 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java @@ -15,15 +15,16 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; /** - * Validator class for checking the existence of entities with the given client reference IDs. - * This validator checks if the provided referral entities already exist in the database based on their client reference IDs. + * Validator class for checking the existence of referral entities with the given client reference IDs. + * This validator checks if the provided Referral entities already exist in the database based on their client reference IDs. + * * @author kanishq-egov */ @Component @@ -36,47 +37,58 @@ public class RmExistentEntityValidator implements Validator> validate(ReferralBulkRequest request) { - // Map to hold referral entities and their error details + // Map to hold Referral entities and their error details Map> errorDetailsMap = new HashMap<>(); - // Get the list of referral entities from the request + + // Get the list of Referral entities from the request List entities = request.getReferrals(); - // Extract client reference IDs from referral entities without errors + + // Extract client reference IDs from Referral entities that do not have existing errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(Referral::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(Referral::getClientReferenceId) // Extract client reference IDs from Referral entities + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map for quick lookup of Referral entities by client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object for querying existing Referral entities by client reference IDs ReferralSearch referralSearch = ReferralSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = referralRepository.findById( - clientReferenceIdList, - getIdFieldName(referralSearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing Referral entities with the given client reference IDs + List existingClientReferenceIds = referralRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding Referral entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual Referral entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing Referral entities and their associated error details return errorDetailsMap; } - } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java index 33e3e750911..de041f238e8 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java @@ -15,14 +15,14 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; /** - * Validator class for checking the existence of entities with the given client reference IDs. + * Validator class for checking the existence of HFReferral entities with the given client reference IDs. * This validator checks if the provided HFReferral entities already exist in the database based on their client reference IDs. * * @author kanishq-egov @@ -44,41 +44,51 @@ public HfrExistentEntityValidator(HFReferralRepository hfReferralRepository) { } /** - * Validates the existence of entities with the given client reference IDs. + * Validates the existence of HFReferral entities in the HFReferralBulkRequest. + * Checks if the provided HFReferral entities already exist in the database based on their client reference IDs. * * @param request The bulk request containing HFReferral entities. - * @return A map containing HFReferral entities and their associated error details. + * @return A map containing HFReferral entities and their associated error details if any duplicates are found. */ @Override public Map> validate(HFReferralBulkRequest request) { - // Map to hold HFReferral entities and their error details + // Map to hold HFReferral entities and their error details. Map> errorDetailsMap = new HashMap<>(); - // Get the list of HFReferral entities from the request + + // Get the list of HFReferral entities from the request. List entities = request.getHfReferrals(); - // Extract client reference IDs from HFReferral entities without errors + + // Extract client reference IDs from HFReferral entities that do not have existing errors. List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(HFReferral::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(HFReferral::getClientReferenceId) // Extract client reference IDs from HFReferral entities. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map for quick lookup of HFReferral entities by client reference ID. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object for querying existing HFReferral entities by client reference IDs. HFReferralSearch hfReferralSearch = HFReferralSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database. if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = hfReferralRepository.findById( - clientReferenceIdList, - Boolean.FALSE, - getIdFieldName(hfReferralSearch) - ); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing HFReferral entities with the given client reference IDs. + List existingClientReferenceIds = hfReferralRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding HFReferral entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual HFReferral entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing HFReferral entities and their associated error details. return errorDetailsMap; } - } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java index 9ed78e8db17..961272cb95d 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -44,39 +44,51 @@ public SeExistentEntityValidator(SideEffectRepository sideEffectRepository) { } /** - * Validates the existence of SideEffect entities with the given client reference IDs. + * Validates the existence of SideEffect entities in the SideEffectBulkRequest. + * Checks if the provided SideEffect entities already exist in the database based on their client reference IDs. * * @param request The bulk request containing SideEffect entities. - * @return A map containing SideEffect entities and their associated error details. + * @return A map containing SideEffect entities and their associated error details if any duplicates are found. */ @Override public Map> validate(SideEffectBulkRequest request) { // Map to hold SideEffect entities and their error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of SideEffect entities from the request List entities = request.getSideEffects(); - // Extract client reference IDs from SideEffect entities without errors + + // Extract client reference IDs from SideEffect entities that do not have existing errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(SideEffect::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(SideEffect::getClientReferenceId) // Extract client reference IDs from SideEffect entities + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map for quick lookup of SideEffect entities by client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object for querying existing SideEffect entities by client reference IDs SideEffectSearch sideEffectSearch = SideEffectSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = sideEffectRepository.findById( - clientReferenceIdList, - getIdFieldName(sideEffectSearch), - Boolean.FALSE); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing SideEffect entities with the given client reference IDs + List existingClientReferenceIds = sideEffectRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding SideEffect entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual SideEffect entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing SideEffect entities and their associated error details return errorDetailsMap; } } diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index fcceea2e322..d204ba58903 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -45,7 +45,7 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java index 7ad90579428..85d5d2bf613 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -53,31 +53,41 @@ public SExistentEntityValidator(StockRepository stockRepository) { public Map> validate(StockBulkRequest request) { // Map to hold Stock entities and their error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of Stock entities from the request List entities = request.getStock(); - // Extract client reference IDs from Stock entities without errors + + // Extract client reference IDs from Stock entities that do not already have errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(Stock::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Exclude entities with existing errors + .map(Stock::getClientReferenceId) // Map entities to their client reference IDs + .collect(Collectors.toList()); // Collect IDs into a list + + // Create a map for quick lookup of Stock entities by their client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object to query existing entities by client reference IDs StockSearch stockSearch = StockSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the list of client reference IDs is not empty if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = stockRepository.findById( - clientReferenceIdList, - Boolean.FALSE, - getIdFieldName(stockSearch) - ); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing Stock entities with the given client reference IDs + List existingClientReferenceIds = stockRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding Stock entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual Stock entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing Stock entities and their associated error details return errorDetailsMap; } } diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java index e7c0ec35d16..6917135941a 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -53,31 +53,42 @@ public SrExistentEntityValidator(StockReconciliationRepository stockReconciliati public Map> validate(StockReconciliationBulkRequest request) { // Map to hold StockReconciliation entities and their error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of StockReconciliation entities from the request List entities = request.getStockReconciliation(); - // Extract client reference IDs from StockReconciliation entities without errors + + // Extract client reference IDs from StockReconciliation entities that do not already have errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(StockReconciliation::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities with existing errors + .map(StockReconciliation::getClientReferenceId) // Map entities to their client reference IDs + .collect(Collectors.toList()); // Collect IDs into a list + + // Create a map for quick lookup of StockReconciliation entities by their client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object to query existing entities by client reference IDs StockReconciliationSearch stockReconciliationSearch = StockReconciliationSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the list of client reference IDs is not empty if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = stockReconciliationRepository.findById( - clientReferenceIdList, - Boolean.FALSE, - getIdFieldName(stockReconciliationSearch) - ); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing StockReconciliation entities with the given client reference IDs + List existingClientReferenceIds = + stockReconciliationRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding StockReconciliation entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual StockReconciliation entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing StockReconciliation entities and their associated error details return errorDetailsMap; } } From 1ea8b5b5b96517e0eab2ae427bb820a544dde191 Mon Sep 17 00:00:00 2001 From: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Date: Mon, 12 Aug 2024 17:02:48 +0530 Subject: [PATCH 02/29] v0.2 admin console merge to master (#849) * Updated the user Password generation logic #761 * Update Listener.ts (#730) * Update Listener.ts * added try catch logic in producer * Feat : added parallel batch execution (#767) * Feat : added parallel batch execution * Refactor * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fixed the stepper (#765) * changes config (#769) * Project type config and added loggers for process of campaign (#772) * Feat : added themes in generate template (#773) * fixed the ajv package version for build issue * Feat : removed xlsx (#776) * HLM-6177: PARALLEL SEARCH IMPLEMENT, DELIVERY TYPE IMPLEMENT (#778) Co-authored-by: nabeelmd-eGov * css update (#780) Co-authored-by: nabeelmd-eGov * HLM-6179 and HLM-6180 (#777) * HLM-6179 and HLM-6180 * campaign name changes --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Feat : fixed target generation (#781) * fixed tenantId issue (#784) * fix: resolved AJV-related Jenkins build issue reference #783 #786 (#787) * module ui fix * updated all the package version for build fixes * fixed kafka-error at target generation (#789) * updated core version (#791) * updated core version * updated css also * Update campaignValidators.ts (#794) * Updated the excel generation logic and files * added changes for configurable column in target sheet (#779) * change in filter recursive * lowest level * made target headers genearte through mdms schema * changed config index.ts * changed config index.ts * changes for now * added configurable column logic from schema HLM-6169 * updated validate of target columns through schema * added masterForColumnSchema in index.ts * formatted dataManageService * refactored lock TargetFields func * removed console.log * User creation performance improved (#800) * Feat : Improved user creation performance * Change status color * Update utilities/project-factory/src/server/utils/campaignUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update genericUtils.ts (#801) * Hlm 6170 (#802) * change in filter recursive * lowest level * HLM -6170 added logic for only village level data in target sheet and some refactoring * updated css (#804) * fixed button issue (#805) * HLM 6177: Error card implementation in summary screen (#806) * HLM-6177: PARALLEL SEARCH IMPLEMENT, DELIVERY TYPE IMPLEMENT * Added Error Cards in summary screen and redirection --------- Co-authored-by: nabeelmd-eGov * added error button styles (#807) Co-authored-by: nabeelmd-eGov * updated popUp css (#808) * HLM 6178: Implementing New Pop up screen in boundaries (#809) * added error button styles * Implementing New Pop up screen in boundaries --------- Co-authored-by: nabeelmd-eGov * Facility changes (#812) * Feat : changed facility Template * Feat : locked target templates * fixed colour issue (#813) * Updated the project type conversion logic for the "deliveryType" dont1 and n config * Unique field added (#814) * Feat : changed facility Template * Feat : locked target templates * Feat : added unique check logic * Target schema update (#815) * change in filter recursive * lowest level * updated shcema of target columns to be configurable * removed empty spaces from config index.ts * Active mapping (#817) * Feat : changed facility Template * Feat : locked target templates * Feat : added unique check logic * Feat : added mapping via active field * changes in the schema validation (#816) * Updated the workbench and css module version * Feat : added active inactive boundary check (#818) * Update campaignValidators.ts (#819) * added active inactive validation (#820) * changed api call time (#826) * Feat : added target sum mapping (#825) * added campaign type as filter (#827) * Update genericApis.ts (#828) * Update excelUtils.ts (#829) * UI issue fixes, icon fix in summary error (#831) Co-authored-by: nabeelmd-eGov * Target columns (#830) * change in filter recursive * lowest level * commit * Feat : target flow fixed for LLIN-mz * uat to dev --------- Co-authored-by: admin1 * Feat : freezed target columns (#833) * Target mr dn (#834) * change in filter recursive * lowest level * Feat : skipped validation temporarily * changes in the target validation (#835) * fixed error info (#837) * Added roboto font (#840) * Feat : added roboto font * Fixed config * target validation based on diff campaign types (#843) * change in filter recursive * lowest level * updated validation of target based on campaign type * fixed validation issue (#844) * Updated the workbench package version * fixed validation logic (#846) * fixed validation logic * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Error messages improved (#848) * Feat : imporved error messages and initilised utils for tracking process * Fix ; unused variables fixed * Feat : improved error messages * Fix : download error fix (#850) * Update campaignUtils.ts (#851) * Update campaignUtils.ts * Update utilities/project-factory/src/server/utils/campaignUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update campaignValidators.ts (#853) * HLM 6210: Toast, error focus fix and project type reset delivery data fix (#854) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix --------- Co-authored-by: nabeelmd-eGov * HLM-6225_added time out according to data (#855) * Update campaignValidators.ts (#859) * HLM 6210 (#858) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix * parallel search fixes --------- Co-authored-by: nabeelmd-eGov * Remove validation (#852) * change in filter recursive * lowest level * removed unnecessary validation for target * spacing refactor * Update campaignValidators.ts (#863) * Header validation (#861) * change in filter recursive * lowest level * removed unnecessary validation for target * changed the logic of header validation * space refactor * Update campaignUtils.ts (#864) * fixed ui error (#865) * Read me (#867) * change in filter recursive * lowest level * removed unnecessary validation for target * changed the logic of header validation * fixed portugese language error * space refactoring * Update Dockerfile * Update Dockerfile * Update migrate.sh * Update Dockerfile * Update campaignValidators.ts (#868) * HLM 6210:campaign type change reset fix (#869) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix * parallel search fixes * campaign type change reset fix --------- Co-authored-by: nabeelmd-eGov * Update excelUtils.ts for sheetHeaders wraping (#870) * Update package.json * updated error messages (#871) * feat : added jaeger-client tracing (#872) * updated the table config * Update campaignApis.ts (#875) * removed the schema and updated the db name * fixing generate API call, file auto delete, date error (#877) Co-authored-by: nabeelmd-eGov * Trim resource (#878) * Feat : trimmed resource persist message * Refactor * Removed reject error in produce message * fixed min time, draft logic (#879) * Update index.ts (#880) * added min ui error and facility usage (#883) * added min ui error and facility usage * changes * Update campaignUtils.ts (#884) * HLM 6007 (#885) * fixing generate API call, file auto delete, date error * generate api fix --------- Co-authored-by: nabeelmd-eGov * Update Dockerfile * Feat : docker config update (#886) * Update Dockerfile (#887) * Create buildWorkbenchUI.yml * Update README.md (#917) * Update buildWorkbenchUI.yml * Update README.md * Updated the DB Schema issue of Project-factory * fixed hierarchy order (#919) * User flag hcm (#920) * Feat : docker config update * Feat : added user create flag * Refactored * Update campaignUtils.ts * Update campaignMappingUtils.ts (#922) * Ashish egov patch 2 (#921) * Update index.ts * Update campaignApis.ts * Fixed the project type conversion and product duplicate issue * Update campaignApis.ts (#924) * Update campaignMappingUtils.ts (#925) * Update campaignMappingUtils.ts * Refactored * Update publishProjectFactory.yml * Update buildWorkbenchUI.yml * Update campaignMappingUtils.ts (#926) * Update request.ts (#928) * Update request.ts * Feat : updated httprequest * Feat : warning response added * Refactor * added start and enddate in cycles * Update campaignApis.ts (#930) * Update request.ts (#932) * fixed generate issue (#933) * Fixed project-type resources duplication * updated target error messages (#936) * fixed stepper from draft (#937) * Update Listener.ts * delivery type disable fix, product sku name change (#939) Co-authored-by: nabeelmd-eGov * fixed error message issue (#941) * Redis integration (#940) * Feat : added redis * Feat : added redis retry * updated migration * Feat : changed download logic (#942) * Update README.md (#943) * fixed target validate for different tabs not present (#945) * Enriching already exsisting user (#946) * Feat : adding dropdowns (#952) * HLM-6270: Date logic changes, added localisation code (#953) Co-authored-by: nabeelmd-eGov * changed maximum target message (#954) * changed maximum target message * Update UploadData.js * Call generate (#951) * updated target error messages * generate call while campaign update changes boundaries * some update on call-generate * call-generate * updated call-gnerate logic * added column campaign id in generated resource table * updated config index.ts * removed console.logs * Update utilities/project-factory/src/server/utils/generateUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/generateUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * added some additional conditions --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * changed facility info message (#955) * HLM 6270 (#957) * refactor * added title text --------- Co-authored-by: nabeelmd-eGov * Update genericUtils.ts (#958) * fixed boundary draft logic (#959) * Boundary code generated has now configurable hierarchy type and boundary name at last based on config (#963) * fixed target validate for different tabs not present * made hierarchytype and bondary name configurable in auto generation of boundary code * added toString() on elment for safety * HLM-6270: Elimated Generate API & enhance download API, Date logic fixes (#966) * refactor * added title text * HLM-6270: Elimated Generate API & enhance download API, Date logic fixes --------- Co-authored-by: nabeelmd-eGov * Ashish table create (#972) * saving * Feat : adding table * Feat : table creating * updated configs * Feat : added table * Feat : table added * Feat : integrated processtracks * Fix : name format (#973) * Update campaignUtils.ts (#974) * configure app static screen and skeleton (#980) * configure app static screen and skeleton * comments resolved * Migration repair (#981) * migration repair * migration repair * migration repair * Updated CampaignCard to add NATIONAL_SUPERVISOR dashboard link * made isActive change (#986) * boundaries on which we split to be fetched from mdms (#982) * fixed target validate for different tabs not present * split boundaries fetch from mdms * updated logic to fetch split on from mdms based on campaign type * fromatting * Update campaignUtils.ts (#988) * Update processTrackUtils.ts (#989) * fixs (#990) * fixs * Update SelectingBoundaries.js * Update processTrackUtils.ts (#991) * Summary screen api loop fix (#992) Co-authored-by: nabeelmd-eGov * Resource activity (#993) * fixed target validate for different tabs not present * resource activity persisting in db * Update processTrackUtils.ts (#994) * added timeout of 2 sec for boundary entity to persist (#996) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * css version fix (#997) Co-authored-by: nabeelmd-eGov * Process tracking update (#998) * Feat : changed logic of process track * Feat : improved process tracks * improved process tracking * Update campaignUtils.ts (#999) * Update campaignUtils.ts (#1000) * Update campaignUtils.ts * Update Listener.ts * Feat : imporved process track (#1001) * Update campaignManageService.ts (#1003) * Update campaignManageService.ts * Update campaignUtils.ts * Update processTrackUtils.ts * Feat : added user mapping for multiple boundaries with common parent (#1005) * new template will be generated if source is microplan accordingly from mdms (#1004) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * new template generate if source is microplan * updated logic for generating templates if source of campaign is from microplan * made separate function for checking source is microplan * added separate func for checking source is microplan * refactor * chnaged the checkIFSourceMicoplan func * refactored checkifsourceismicroplan * Fix : fix array fetch from cell (#1006) * Feat : fixed array issue in target (#1007) * Feat : fixed array issue in target * Update index.ts * Some fixes and refactor (#1008) * Feat : fixed array issue in target * Update index.ts * Refactor * Fixed status row * commented harcoded check && added new dashboard icon (#1011) Co-authored-by: nabeelmd-eGov * Fixed sheetrows issues (#1012) * Sheet row fixed (#1013) * Fixed sheetrows issues * Shut down if kafka error * Feat : formated sheet (#1015) * integrated admin schema with mdms_v2 (#1018) * Fix process timeline (#1029) * Feat : formated sheet * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Feat : imporved processTracking and fixed migration script * Feat : fixed error persistence * Fix * Un wrap other rows (#1034) * Feat : formated sheet * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Feat : imporved processTracking and fixed migration script * Feat : fixed error persistence * Unwraped lower rows * Update publishProjectFactory.yml * updated package versions (#1042) * HLM-6325/HLM-6277: Update date with & without boundary screen integration and actionable column added (#1045) * HLM-6007 * css version fix * update date screen added * change add * css fixes and API Integration for search project * Implemented Action component in My Campaign screen * Implemented Date Update with and without boundary with API integration * Boundary change --------- Co-authored-by: nabeelmd-eGov * Facility dynamic generate for source microplan (#1046) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * added code for generating facility template if source is microplan * updated name * updated version (#1047) * updated core version to fix login forget password issues(#1051) * Fixed update topic (#1056) * updated version (#1061) * Hidden sheet impel (#1077) * Feat : formated sheet * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Feat : imporved processTracking and fixed migration script * Feat : fixed error persistence * Unwraped lower rows * Update campaignUtils.ts * Update publishProjectFactory.yml * Update genericUtils.ts (#1078) * target template download based on delivery conditions if present (#1080) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * logic for dynamic target generate template based on delivery conditions * fixed stepper color issue from draft (#1083) * fixed reordering of tab issue (#1092) * Hlm 6350 (#1094) * timeline wip * added timeline from summary * removed log * integarte with mdms (#1095) Co-authored-by: nabeelmd-eGov * Update genericUtils.ts (#1097) * Update targetUtils.ts (#1098) * Hlm 6350 (#1100) * timeline wip * added timeline from summary * removed log * integrated timeline with popup * updated version * updated css version * HCMPRE-32: Resolve date update demo points (#1104) * integarte with mdms * HCMPRE-32: Resolve date update demo points * comment resolve --------- Co-authored-by: nabeelmd-eGov * Dynamic target upload and download both with target columns as per delivery conditions when campaign is updated with cahnegs in delivery conditions (#1109) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * target upload based on dynamic column in reference to deliveryRules * logic for calling generate target tempalte when campaign delivery conditions change * removed console * updated css version (#1102) * added chip for dropdown (#1111) * version fix to resolve issue (#1112) Co-authored-by: nabeelmd-eGov * Ashish patch1 (#1118) * Feat : formated sheet * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Feat : imporved processTracking and fixed migration script * Feat : fixed error persistence * Unwraped lower rows * Update campaignUtils.ts * Update genericValidator.ts * Update publishProjectFactory.yml * Update targetUtils.ts * edit product with prefilled value and count (#1115) * Boundary upload to have not generate boundary code if code is already filled to support migration (#1121) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * Boundary upload to have not generate boundary code if code is already filled to support migration * Update index.ts * Update constants.ts (#1122) * Update constants.ts * Update utilities/project-factory/src/server/config/constants.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update campaignUtils.ts * Update campaignUtils.ts * Update campaignMappingUtils.ts --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * template downlod for source microplan (#1123) * Different tabs onlevel to fetch from mdms rather than from config in target upload flow (#1124) * template downlod for source microplan * updated logic for getting different tabs based on level from config to fetch it from mdms in target upload flow * Sequence order change in action button (#1125) Co-authored-by: nabeelmd-eGov * reverted the function validateAllDistrictTabsPresentOrNot (#1126) * template downlod for source microplan * updated logic for getting different tabs based on level from config to fetch it from mdms in target upload flow * restored the func validateAllDistrictTabsPresentOrNot to default * Update index.ts (#1129) * Update index.ts * Update Listener.ts * Update Producer.ts * Update generateUtils.ts (#1130) * some changes related to generate boundary template (#1133) * updated logic for target columns acc to delivery conditions only for smc (#1137) * some changes related to generate boundary template * updated logic for making configurable target acc to delivery only for smc * refactored code for including dynamic target columns for specific types according to configs array * updated version and boundary fix (#1141) * updated readmeconfig for sheet (#1142) * HCMPRE-140: Action column fixes, date editable logic change (#1143) * Action column fixes, date editable logic change * added roles for dss --------- Co-authored-by: nabeelmd-eGov * Update constants.ts (#1145) * Update constants.ts * Update processTrackUtils.ts * Update Listener.ts (#1147) * HCMPRE 140 (#1149) * Action column fixes, date editable logic change * added roles for dss * update dates fixes --------- Co-authored-by: nabeelmd-eGov * updated core version (#1150) * Ashish patch2 (#1152) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Update publishProjectFactory.yml * Redis cache for generating target when delivery conditions change (#1156) * updated readmeconfig for sheet * added cache for generating target template when only delivery conditions change * added cache time in config * refactored caching code in generate flow for boundary sheet * refactored callGenerate function * Ashish egov patch 2 (#1166) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Update publishProjectFactory.yml * HCMPRE-154: Update Dates bug fixes, Toast added for error. (#1158) * Action column fixes, date editable logic change * added roles for dss * update dates fixes * HCMPRE-154 update dates bug fixes, Added toast for error * code clean * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BoundaryWithDate.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Adding date bug * date fix * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DateWithBoundary.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DateWithBoundary.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: nabeelmd-eGov Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * version update (#1168) Co-authored-by: nabeelmd-eGov * HCMPRE-6407 download template changes (#1128) * HLM-6407 adding changes for facility template * HLM-6407 adding changes for facility template * HLM-6407 adding changes for facility template * HLM-6407 codde review comment * HCMPRE-91 code review comments * HLM-6407 using same mdms schema for microplan * HLM-6407 adding changes for facility template * HLM-6407 adding changes for facility template * HLM-6407 adding changes for facility template * HLM-6407 codde review comment * HCMPRE-91 code review comments * HLM-6407 using same mdms schema for microplan * HLM-6407 code review comments * HLM-6407 code review comments * Core ui version fix (#1176) Co-authored-by: nabeelmd-eGov * Ashish egov patch 2 (#1178) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Producer update * Update publishProjectFactory.yml * Update Producer.ts (#1182) * fixed timeline issues (#1185) * HCMPRE 154 (#1186) * date validation fix * Update date logic * FIX --------- Co-authored-by: nabeelmd-eGov * changes in timeline (#1187) * CSS version add (#1188) * date validation fix * Update date logic * FIX * css add --------- Co-authored-by: nabeelmd-eGov * HCMPRE 154 (#1189) * date validation fix * Update date logic * FIX * css add * non editable fix --------- Co-authored-by: nabeelmd-eGov * limited the number of columns of target for upto only 18 in number (#1190) * updated readmeconfig for sheet * added cache for generating target template when only delivery conditions change * added logic for having only 18 target columns if exceed i will create one column with header OTHER_TARGETS * HCMPRE 154 (#1191) * date validation fix * Update date logic * FIX * css add * non editable fix * date start from tomorrow * css fix for language screen --------- Co-authored-by: nabeelmd-eGov * Produceasync (#1192) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Producer update * Feat : updated producemodified message * Update publishProjectFactory.yml * Update publishProjectFactory.yml * HCMPRE 154 (#1193) * date validation fix * Update date logic * FIX * css add * non editable fix * date start from tomorrow * css fix for language screen * disable today date --------- Co-authored-by: nabeelmd-eGov * config updates according to devops (#1197) * updated readmeconfig for sheet * added cache for generating target template when only delivery conditions change * added logic for having only 18 target columns if exceed i will create one column with header OTHER_TARGETS * updated config to fetch from devops accordingly * Update index.ts * All changes (#1201) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Producer update * Update Producer.ts * Update Producer.ts * Feat : updated producemodified message * Feat : removed waiting * adding constraint * Update V20240731162600__add_uniqiue_constraint_process_track.sql * Update constants.ts * Update publishProjectFactory.yml * HCMPRE 154 (#1202) * date validation fix * Update date logic * FIX * css add * non editable fix * date start from tomorrow * css fix for language screen * disable today date * date and cycle fix --------- Co-authored-by: nabeelmd-eGov * Revert "HCMPRE 154 (#1191)" (#1203) This reverts commit 59ec9531ebfc7535bacf324723edae975166867c. Co-authored-by: nabeelmd-eGov * updated versions (#1205) * Update date change screen date logic fix, info added, hard reload issue fix (#1206) Co-authored-by: nabeelmd-eGov * Config update for project-factory (#1207) * updated readmeconfig for sheet * added cache for generating target template when only delivery conditions change * added logic for having only 18 target columns if exceed i will create one column with header OTHER_TARGETS * updated config to fetch from devops accordingly * updated config for project -factory * Timeline (#1210) * updated versions * fixed user credential button * Kafka fix (#1212) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Producer update * Revert "Ashish egov patch 2 (#1178)" This reverts commit e86a4dcb10dda9210ce4be75977502af7df366f6. * Update Producer.ts * Update Producer.ts * Feat : updated producemodified message * Feat : removed waiting * adding constraint * Update V20240731162600__add_uniqiue_constraint_process_track.sql * Update constants.ts * Feat : improved kafka * Fix kafka restart issue * fixed the pop up button issue (#1215) * Kafka restart (#1217) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Producer update * Revert "Ashish egov patch 2 (#1178)" This reverts commit e86a4dcb10dda9210ce4be75977502af7df366f6. * Update Producer.ts * Update Producer.ts * Feat : updated producemodified message * Feat : removed waiting * adding constraint * Update V20240731162600__add_uniqiue_constraint_process_track.sql * Update constants.ts * Feat : improved kafka * Update Producer.ts * Update Producer.ts * Update publishProjectFactory.yml * updated core versions for privacy component (#1223) * Ashish egov patch 1 (#1228) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Producer update * Revert "Ashish egov patch 2 (#1178)" This reverts commit e86a4dcb10dda9210ce4be75977502af7df366f6. * Update Producer.ts * Update Producer.ts * Feat : updated producemodified message * Feat : removed waiting * adding constraint * Update V20240731162600__add_uniqiue_constraint_process_track.sql * Update constants.ts * Feat : improved kafka * Update Producer.ts * Update Producer.ts * Update campaignUtils.ts * feat : solved localization passing through kafka * Update publishProjectFactory.yml * removed frontend * Update package.json * Squashed commit of the following: commit 3cd21c29c69ab52c960b6d770fe97e85f24c23e4 Merge: 12061ca60e 80f6307123 Author: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Thu Aug 8 15:13:48 2024 +0530 Merge branch 'campaign' into campaign-merged commit 80f6307123c86998364e311757a46f256bd69005 Author: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Date: Wed Aug 7 18:08:15 2024 +0530 Updated changelog (#1242) * default enableDynamicTemplateForWillBe empty string in config * updated changelog and postman collection commit f897dba734e05e55fa1231a81a2e5f86612825a3 Author: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Wed Aug 7 17:25:39 2024 +0530 Update package.json commit dd691e6a26aff0a5131736086b447995ae3f0757 Author: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Date: Tue Aug 6 13:34:40 2024 +0530 updated workbench version (#1236) commit 3a3073649791815766745c60f48db3fea4fbe7f1 Author: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Date: Tue Aug 6 11:00:14 2024 +0530 updated micro ui core version (#1233) commit a1f7329c88254f4cd6ab3db2fa06c3259699f2e2 Author: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Date: Mon Aug 5 18:29:40 2024 +0530 default enableDynamicTemplateForWillBe empty string in config (#1231) commit d3c3e95408f7bf25205b6b57a3e109d8eea0af2c Author: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Date: Mon Aug 5 18:11:23 2024 +0530 build issue fix for optional chanining issue (#1230) Co-authored-by: nabeelmd-eGov commit 236b8439d9e24a5ecd0494f76ad2504ca693fe31 Author: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Date: Mon Aug 5 17:17:20 2024 +0530 fix (#1229) Co-authored-by: nabeelmd-eGov * sending only activity object to kafka in place of request body (#851) --------- Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> --- .vscode/launch.json | 18 + .vscode/settings.json | 3 + frontend/micro-ui/.gitignore | 32 - frontend/micro-ui/Jenkinsfile | 3 - frontend/micro-ui/README.md | 139 - frontend/micro-ui/package.json | 4 - frontend/micro-ui/web/.babelrc | 5 - frontend/micro-ui/web/.env.sample | 3 - frontend/micro-ui/web/CHANGELOG.md | 7 - frontend/micro-ui/web/docker/Dockerfile | 25 - frontend/micro-ui/web/docker/devDockerfile | 26 - frontend/micro-ui/web/docker/masDockerfile | 25 - frontend/micro-ui/web/docker/nginx.conf | 12 - frontend/micro-ui/web/envs.js | 0 frontend/micro-ui/web/install-deps.sh | 14 - .../web/micro-ui-internals/.gitignore | 143 - .../web/micro-ui-internals/.prettierignore | 23 - .../web/micro-ui-internals/.prettierrc.json | 3 - .../micro-ui/web/micro-ui-internals/README.md | 100 - .../micro-ui/web/micro-ui-internals/clean.sh | 28 - .../micro-ui-internals/example/.env-health-qa | 7 - .../micro-ui-internals/example/.env-mz-prod | 7 - .../micro-ui-internals/example/.env-mz-uat | 7 - .../example/.env-unifieddev | 9 - .../micro-ui-internals/example/package.json | 40 - .../example/public/index.html | 34 - .../example/src/UICustomizations.js | 789 ----- .../micro-ui-internals/example/src/index.js | 84 - .../example/src/setupProxy.js | 101 - .../web/micro-ui-internals/package.json | 59 - .../micro-ui-internals/packages/css/README.md | 62 - .../packages/css/gulpfile.js | 71 - .../packages/css/package.json | 65 - .../packages/css/postcss.config.js | 55 - .../css/src/components/microplanning.scss | 363 -- .../packages/css/src/index.scss | 13 - .../css/src/pages/employee/campaign.scss | 109 - .../css/src/pages/employee/campaignCycle.scss | 331 -- .../css/src/pages/employee/coreOverride.scss | 173 - .../css/src/pages/employee/index.scss | 481 --- .../packages/css/src/typography.scss | 512 --- .../packages/css/tailwind.config.js | 233 -- .../modules/campaign-manager/README.md | 159 - .../modules/campaign-manager/package.json | 51 - .../modules/campaign-manager/src/Module.js | 141 - .../src/components/AddProductField.js | 144 - .../src/components/BulkUpload.js | 202 -- .../src/components/CampaignCard.js | 71 - .../src/components/CampaignDates.js | 122 - .../components/CampaignDocumentsPreview.js | 92 - .../src/components/CampaignHeader.js | 32 - .../src/components/CampaignName.js | 66 - .../components/CampaignResourceDocuments.js | 50 - .../src/components/CampaignSummary.js | 484 --- .../src/components/CampaignType.js | 143 - .../src/components/CycleDataPreview.js | 186 - .../src/components/CycleDetaisPreview.js | 143 - .../src/components/DetailsTable.js | 76 - .../src/components/DocumentIcon.js | 29 - .../src/components/PlusMinusInput.js | 47 - .../src/components/RemovableTagNew.js | 16 - .../src/components/SelectingBoundaries.js | 542 --- .../src/components/TimelineCampaign.js | 46 - .../src/components/UploadData.js | 1163 ------- .../src/components/XlsPreview.js | 69 - .../src/components/icons/DustbinIcon.js | 10 - .../src/components/icons/XlsxFile.js | 32 - .../src/configs/CampaignConfig.js | 267 -- .../src/configs/UICustomizations.js | 472 --- .../src/configs/addProductConfig.js | 19 - .../src/configs/attributeConfig.js | 23 - .../src/configs/baseTimeOut.js | 6 - .../src/configs/deliveryConfig.js | 206 -- .../src/configs/headerConfig.js | 20 - .../src/configs/mailConfig.js | 5 - .../src/configs/myCampaignConfig.js | 667 ---- .../src/configs/operatorConfig.js | 27 - .../src/configs/previewConfig.js | 124 - .../src/configs/productType.js | 15 - .../src/configs/schemaConfig.js | 80 - .../campaign-manager/src/hooks/index.js | 47 - .../hooks/services/createCampaignService.js | 19 - .../hooks/services/updateCampaignService.js | 20 - .../src/hooks/services/useSearchCampaign.js | 21 - .../src/hooks/useCreateCampaign.js | 10 - .../src/hooks/useCreateProduct.js | 24 - .../src/hooks/useCreateProductVariant.js | 24 - .../src/hooks/useGenerateIdCampaign.js | 26 - .../src/hooks/useParallelSearch.js | 88 - .../src/hooks/useProductList.js | 53 - .../src/hooks/useResourceData.js | 107 - .../src/hooks/useUpdateCampaign.js | 10 - .../src/pages/employee/AddProduct.js | 161 - .../src/pages/employee/CycleConfiguration.js | 248 -- .../src/pages/employee/MyCampaign.js | 80 - .../src/pages/employee/Response.js | 65 - .../src/pages/employee/SetupCampaign.js | 1491 -------- .../deliveryRule/AddDeliverycontext.js | 813 ----- .../deliveryRule/AddProductscontext.js | 290 -- .../employee/deliveryRule/MultiTabcontext.js | 265 -- .../src/pages/employee/deliveryRule/index.js | 531 --- .../src/pages/employee/index.js | 102 - .../campaign-manager/src/utils/TourSteps.js | 144 - .../src/utils/downloadExcel.js | 46 - .../campaign-manager/src/utils/index.js | 6 - .../modules/hcm-microplanning/package.json | 62 - .../modules/hcm-microplanning/src/Module.js | 99 - .../src/components/CommonComponents.js | 61 - .../src/components/CustomScaleControl.js | 41 - .../src/components/Hypothesis.js | 607 ---- .../src/components/JsonPreviewInExcelForm.js | 113 - .../src/components/Mapping.js | 445 --- .../src/components/MappingHelperComponents.js | 513 --- .../src/components/MicroplanCreatedScreen.js | 111 - .../src/components/MicroplanDetails.js | 294 -- .../src/components/MicroplanPreview.js | 478 --- .../MicroplanPreviewHelperCompoenents.js | 434 --- .../src/components/MicroplanningCard.js | 34 - .../src/components/MicroplanningHeader.js | 29 - .../hcm-microplanning/src/components/Modal.js | 158 - .../src/components/Nagivator.js | 272 -- .../src/components/RuleEngine.js | 876 ----- .../src/components/Upload.js | 1137 ------- .../src/components/UploadHelperComponents.js | 299 -- .../src/components/ZoomControl.js | 29 - .../src/components/resourceMapping.js | 187 - .../src/configs/UICustomizations.js | 324 -- .../src/configs/constants.js | 36 - .../src/configs/timeLineOptions.json | 40 - .../src/configs/tourSteps.js | 193 -- .../hcm-microplanning/src/hooks/index.js | 42 - .../src/hooks/useCreatePlanConfig.js | 8 - .../src/hooks/useGenerateIdCampaign.js | 26 - .../src/hooks/useNumberFormatter.js | 21 - .../src/hooks/useSavedMicroplans.js | 23 - .../src/hooks/useSearchCampaign.js | 8 - .../src/hooks/useSearchPlanConfig.js | 8 - .../src/hooks/useUpdatePlanConfig.js | 8 - .../hcm-microplanning/src/icons/Svg.js | 217 -- .../src/pages/employee/CreateMicroplan.js | 288 -- .../src/pages/employee/Guidelines.js | 54 - .../src/pages/employee/SavedMicroplans.js | 200 -- .../src/pages/employee/SelectCampaign.js | 226 -- .../src/pages/employee/index.js | 128 - .../src/services/CreatePlanConfig.js | 19 - .../hcm-microplanning/src/services/Search.js | 181 - .../src/services/SearchCampaignConfig.js | 22 - .../src/services/SearchPlanConfig.js | 19 - .../src/services/UpdatePlanConfig.js | 18 - .../src/services/searchSavedPlans.js | 67 - .../hcm-microplanning/src/utils/context.js | 31 - .../src/utils/createTemplate.js | 485 --- .../hcm-microplanning/src/utils/excelUtils.js | 150 - .../src/utils/excelValidations.js | 199 -- .../src/utils/exceltojson.js | 99 - .../src/utils/geojsonValidations.js | 234 -- .../hcm-microplanning/src/utils/index.js | 478 --- .../src/utils/jsonToExcelBlob.js | 72 - .../src/utils/mappingUtils.js | 760 ----- .../src/utils/microplanPreviewUtils.js | 413 --- .../src/utils/processHierarchyAndData.js | 351 -- .../src/utils/updateSessionUtils.js | 486 --- .../src/utils/uploadUtils.js | 880 ----- .../Modal/AttendanceActionModal.js | 133 - .../Modal/BPAActionModal.js | 283 -- .../Modal/BPAREGActionModal.js | 153 - .../Modal/ExpenditureActionModal.js | 190 -- .../Modal/FSMActionModal.js | 298 -- .../Modal/NOCActionModal.js | 169 - .../ApplicationDetails/Modal/PTActionModal.js | 190 -- .../ApplicationDetails/Modal/TLActionModal.js | 166 - .../Modal/WNSActionModal.js | 261 -- .../Modal/WorksActionModal.js | 262 -- .../ApplicationDetails/Modal/index.js | 49 - .../components/ApplicationDetailsActionBar.js | 80 - .../components/ApplicationDetailsContent.js | 484 --- .../components/ApplicationDetailsToast.js | 74 - .../ApplicationDetailsWarningPopup.js | 54 - .../components/BPADocuments.js | 234 -- .../components/DocumentsPreview.js | 49 - .../components/InfoDetails.js | 34 - .../components/InspectionReport.js | 49 - .../components/NOCDocuments.js | 202 -- .../components/PermissionCheck.js | 87 - .../components/PropertyDocuments.js | 83 - .../components/PropertyEstimates.js | 39 - .../components/PropertyFloors.js | 49 - .../components/PropertyOwners.js | 94 - .../ApplicationDetails/components/Reason.js | 10 - .../components/ScruntinyDetails.js | 46 - .../components/SubOccupancyTable.js | 126 - .../components/SubWorkTableDetails.js | 77 - .../components/TLCaption.js | 34 - .../components/TLTradeAccessories.js | 52 - .../components/TLTradeUnits.js | 51 - .../components/ViewBreakup.js | 73 - .../components/WSAdditonalDetails.js | 399 --- .../components/WSFeeEstimation.js | 346 -- .../components/WeekDateRange.js | 30 - .../ApplicationDetails/config/AcceptDso.js | 45 - .../ApplicationDetails/config/AssignDso.js | 115 - .../config/BPAApproverApplication.js | 77 - .../config/BPAREGApproverApplication.js | 71 - .../config/CompleteApplication.js | 46 - .../config/NOCApproverApplication.js | 79 - .../config/PTApproverApplication.js | 66 - .../config/PTAssessProperty.js | 26 - .../ApplicationDetails/config/ReassignDso.js | 101 - .../config/RejectApplication.js | 31 - .../config/TLApproverApplication.js | 83 - .../config/WSApproverApplication.js | 73 - .../config/WSDisconnectApplication.js | 89 - .../config/configApproveModal.js | 53 - .../config/configAttendanceApproveModal.js | 27 - .../config/configAttendanceCheckModal.js | 93 - .../config/configAttendanceRejectModal.js | 61 - .../config/configCheckModal.js | 105 - .../config/configRejectModal.js | 127 - .../config/configViewBillApproveModal.js | 57 - .../config/configViewBillCheckModal.js | 107 - .../config/configViewBillRejectModal.js | 59 - .../ApplicationDetails/config/index.js | 47 - .../templates/ApplicationDetails/index.js | 368 -- .../web/micro-ui-internals/publish-develop.sh | 20 - .../web/micro-ui-internals/publish.sh | 20 - .../web/micro-ui-internals/scripts/create.sh | 3 - .../web/micro-ui-internals/scripts/deploy.sh | 8 - .../web/micro-ui-internals/scripts/jenkins.sh | 3 - .../web/micro-ui-internals/scripts/run.sh | 32 - .../micro-ui/web/micro-ui-internals/test.js | 31 - frontend/micro-ui/web/microplan/App.js | 61 - frontend/micro-ui/web/microplan/Dockerfile | 30 - .../micro-ui/web/microplan/install-deps.sh | 18 - .../micro-ui/web/microplan/inter-package.json | 61 - frontend/micro-ui/web/microplan/nginx.conf | 12 - frontend/micro-ui/web/microplan/package.json | 80 - .../micro-ui/web/microplan/webpack.config.js | 52 - frontend/micro-ui/web/package.json | 85 - frontend/micro-ui/web/public/index.html | 38 - frontend/micro-ui/web/public/robots.txt | 3 - frontend/micro-ui/web/src/App.js | 74 - .../micro-ui/web/src/ComponentRegistry.js | 11 - .../src/Customisations/UICustomizations.js | 428 --- .../micro-ui/web/src/Customisations/index.js | 19 - .../web/src/Customisations/pt/index.js | 13 - .../pt/pageComponents/PTAllotmentDetails.js | 64 - .../pt/pageComponents/PTBusinessDetails.js | 68 - .../pt/pageComponents/PTVasikaDetails.js | 79 - .../pt/pageComponents/PropertyUsageType.js | 134 - .../src/Customisations/tl/TLCustomisation.js | 5 - .../web/src/Customisations/tl/index.js | 7 - .../tl/pageComponents/PropertyUsageType.js | 136 - frontend/micro-ui/web/src/index.css | 0 frontend/micro-ui/web/src/index.js | 62 - frontend/micro-ui/web/src/setupProxy.js | 30 - frontend/micro-ui/web/webpack.config.js | 43 - frontend/micro-ui/web/workbench/App.js | 72 - frontend/micro-ui/web/workbench/Dockerfile | 29 - .../micro-ui/web/workbench/install-deps.sh | 18 - .../micro-ui/web/workbench/inter-package.json | 58 - frontend/micro-ui/web/workbench/nginx.conf | 12 - frontend/micro-ui/web/workbench/package.json | 89 - .../micro-ui/web/workbench/webpack.config.js | 44 - health-services/project-factory/CHANGELOG.md | 6 + health-services/project-factory/README.md | 125 +- ...enerated_resource_details_alter_column.sql | 13 + .../V20240625141100__process_details_ddl.sql | 11 + ...generated_resource_detail_alter_column.sql | 24 + ...100__remove_constraint_process_details.sql | 3 + ...__add_uniqiue_constraint_process_track.sql | 10 + .../project-factory/migration/migrate.sh | 1 + .../project-factory/package-lock.json | 2993 ++++++++--------- health-services/project-factory/package.json | 3 +- .../project-factory/postman_collection.json | 413 ++- .../src/server/api/campaignApis.ts | 132 +- .../src/server/api/genericApis.ts | 281 +- .../src/server/config/constants.ts | 41 +- .../src/server/config/createAndSearch.ts | 132 + .../src/server/config/index.ts | 11 +- .../config/models/createRequestSchema.ts | 2 +- .../config/models/downloadRequestSchema.ts | 20 +- .../config/models/generateRequestSchema.ts | 2 - .../campaignManage.controller.ts | 21 +- .../src/server/kafka/Listener.ts | 112 +- .../src/server/kafka/Producer.ts | 124 +- .../server/service/campaignManageService.ts | 23 +- .../src/server/service/dataManageService.ts | 39 +- .../src/server/utils/campaignMappingUtils.ts | 343 +- .../src/server/utils/campaignUtils.ts | 197 +- .../src/server/utils/excelUtils.ts | 90 +- .../src/server/utils/generateUtils.ts | 85 + .../src/server/utils/genericUtils.ts | 311 +- .../src/server/utils/localisationUtils.ts | 34 +- .../src/server/utils/processTrackUtils.ts | 234 +- .../src/server/utils/targetUtils.ts | 137 + .../server/validators/campaignValidators.ts | 180 +- .../src/server/validators/genericValidator.ts | 54 +- health-services/project-factory/yarn.lock | 835 +++-- 298 files changed, 4307 insertions(+), 39852 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json delete mode 100644 frontend/micro-ui/.gitignore delete mode 100644 frontend/micro-ui/Jenkinsfile delete mode 100644 frontend/micro-ui/README.md delete mode 100644 frontend/micro-ui/package.json delete mode 100644 frontend/micro-ui/web/.babelrc delete mode 100644 frontend/micro-ui/web/.env.sample delete mode 100644 frontend/micro-ui/web/CHANGELOG.md delete mode 100644 frontend/micro-ui/web/docker/Dockerfile delete mode 100644 frontend/micro-ui/web/docker/devDockerfile delete mode 100644 frontend/micro-ui/web/docker/masDockerfile delete mode 100644 frontend/micro-ui/web/docker/nginx.conf delete mode 100644 frontend/micro-ui/web/envs.js delete mode 100755 frontend/micro-ui/web/install-deps.sh delete mode 100644 frontend/micro-ui/web/micro-ui-internals/.gitignore delete mode 100644 frontend/micro-ui/web/micro-ui-internals/.prettierignore delete mode 100644 frontend/micro-ui/web/micro-ui-internals/.prettierrc.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/README.md delete mode 100644 frontend/micro-ui/web/micro-ui-internals/clean.sh delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/package.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/public/index.html delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/package.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/README.md delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/package.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignCard.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignHeader.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignResourceDocuments.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDataPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/baseTimeOut.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddProductscontext.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/publish-develop.sh delete mode 100644 frontend/micro-ui/web/micro-ui-internals/publish.sh delete mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/create.sh delete mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh delete mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh delete mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/run.sh delete mode 100644 frontend/micro-ui/web/micro-ui-internals/test.js delete mode 100644 frontend/micro-ui/web/microplan/App.js delete mode 100644 frontend/micro-ui/web/microplan/Dockerfile delete mode 100644 frontend/micro-ui/web/microplan/install-deps.sh delete mode 100644 frontend/micro-ui/web/microplan/inter-package.json delete mode 100644 frontend/micro-ui/web/microplan/nginx.conf delete mode 100644 frontend/micro-ui/web/microplan/package.json delete mode 100644 frontend/micro-ui/web/microplan/webpack.config.js delete mode 100644 frontend/micro-ui/web/package.json delete mode 100644 frontend/micro-ui/web/public/index.html delete mode 100644 frontend/micro-ui/web/public/robots.txt delete mode 100644 frontend/micro-ui/web/src/App.js delete mode 100644 frontend/micro-ui/web/src/ComponentRegistry.js delete mode 100644 frontend/micro-ui/web/src/Customisations/UICustomizations.js delete mode 100644 frontend/micro-ui/web/src/Customisations/index.js delete mode 100644 frontend/micro-ui/web/src/Customisations/pt/index.js delete mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js delete mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js delete mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js delete mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js delete mode 100644 frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js delete mode 100644 frontend/micro-ui/web/src/Customisations/tl/index.js delete mode 100644 frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js delete mode 100644 frontend/micro-ui/web/src/index.css delete mode 100644 frontend/micro-ui/web/src/index.js delete mode 100644 frontend/micro-ui/web/src/setupProxy.js delete mode 100644 frontend/micro-ui/web/webpack.config.js delete mode 100644 frontend/micro-ui/web/workbench/App.js delete mode 100644 frontend/micro-ui/web/workbench/Dockerfile delete mode 100755 frontend/micro-ui/web/workbench/install-deps.sh delete mode 100644 frontend/micro-ui/web/workbench/inter-package.json delete mode 100644 frontend/micro-ui/web/workbench/nginx.conf delete mode 100644 frontend/micro-ui/web/workbench/package.json delete mode 100644 frontend/micro-ui/web/workbench/webpack.config.js create mode 100644 health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql create mode 100644 health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql create mode 100644 health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql create mode 100644 health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql create mode 100644 health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql create mode 100644 health-services/project-factory/src/server/utils/generateUtils.ts create mode 100644 health-services/project-factory/src/server/utils/targetUtils.ts diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000000..d61e0ddfd7d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "node", + "request": "attach", + "name": "Attach to Remote", + "address": "localhost", + "port": 9229, + "localRoot": "${workspaceFolder}", + "remoteRoot": "/app" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..14f60307eb1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.inlineSuggest.showToolbar": "onHover" +} \ No newline at end of file diff --git a/frontend/micro-ui/.gitignore b/frontend/micro-ui/.gitignore deleted file mode 100644 index feb4cac5c94..00000000000 --- a/frontend/micro-ui/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -.env -.eslintcache - -# yarn $ -.yarn -yarn.lock -.yarnrc.yml - -# dependencies -node_modules -.yarn -/.pnp -.pnp.js - -# testing -/coverage - -# production -/web/build -dist -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/frontend/micro-ui/Jenkinsfile b/frontend/micro-ui/Jenkinsfile deleted file mode 100644 index 1206b9c141d..00000000000 --- a/frontend/micro-ui/Jenkinsfile +++ /dev/null @@ -1,3 +0,0 @@ -library 'ci-libs' - -buildPipeline(configFile: './build/build-config.yml') diff --git a/frontend/micro-ui/README.md b/frontend/micro-ui/README.md deleted file mode 100644 index 9f559d81783..00000000000 --- a/frontend/micro-ui/README.md +++ /dev/null @@ -1,139 +0,0 @@ - -# DIGIT ui - -A React App built on top of DIGIT UI Core. - -# DIGIT - -DIGIT eGovernance Platform Services - -DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://core.digit.org/ for more details. - -DIGIT platform is microservices based API platform enabling quick rebundling of services as per specific needs. This is a repo that lays down the core platform on top of which other mission services depend. - - -# DIGIT UI - - -This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries. - -Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications - -It is also used to manage the Localisation data present in the system (Localisation service) - - -## Run Locally - -Clone the project - -```bash - git clone https://github.com/egovernments/DIGIT-Frontend.git -``` - -Go to the Sub directory to run UI -```bash - cd into micro-ui/web/micro-ui-internals -``` - -Install dependencies - -```bash - yarn install -``` - -Add .env file -```bash - micro-ui/web/micro-ui-internals/example/.env -``` - -Start the server - -```bash - yarn start -``` - - -## Environment Variables - -To run this project, you will need to add the following environment variables to your .env file - -`REACT_APP_PROXY_API` :: `{{server url}}` - -`REACT_APP_GLOBAL` :: `{{server url}}` - -`REACT_APP_PROXY_ASSETS` :: `{{server url}}` - -`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}` - -`SKIP_PREFLIGHT_CHECK` :: `true` - -[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev) - -## Tech Stack - -**Libraries:** - -[React](https://react.dev/) - -[React Hook Form](https://www.react-hook-form.com/) - -[React Query](https://tanstack.com/query/v3/) - -[Tailwind CSS](https://tailwindcss.com/) - -[Webpack](https://webpack.js.org/) - -## License - -[MIT](https://choosealicense.com/licenses/mit/) - - -## Author - -- [@jagankumar-egov](https://www.github.com/jagankumar-egov) - - -## Documentation - -[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) - - -## Support - -For support, add the issues in https://github.com/egovernments/DIGIT-core/issues. - - -## Modules - - 1. Core - 2. Workbench - 3. HRMS - 4. Dashboard - 5. Engagement - 6. Payment - -## Starting with Digit-UI App (Impelmentation Teams) - MICRO-UI - - -Go to the Sub directory to run UI - -```bash - cd into micro-ui/web -``` - -```bash - yarn install -``` - -Add .env file -```bash - micro-ui/web/.env -``` - -Start the server - -```bash - yarn start -``` - -![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) diff --git a/frontend/micro-ui/package.json b/frontend/micro-ui/package.json deleted file mode 100644 index 78ab4e7aa40..00000000000 --- a/frontend/micro-ui/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "workbench-ui", - "version": "0.1.0" -} \ No newline at end of file diff --git a/frontend/micro-ui/web/.babelrc b/frontend/micro-ui/web/.babelrc deleted file mode 100644 index 5f90443d15e..00000000000 --- a/frontend/micro-ui/web/.babelrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "presets": [ - "@babel/preset-env","@babel/preset-react" - ] - } \ No newline at end of file diff --git a/frontend/micro-ui/web/.env.sample b/frontend/micro-ui/web/.env.sample deleted file mode 100644 index e87c7f586c4..00000000000 --- a/frontend/micro-ui/web/.env.sample +++ /dev/null @@ -1,3 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_STATE_LEVEL_TENANT_ID=pb -REACT_APP_PROXY_URL=https://works-dev.digit.org diff --git a/frontend/micro-ui/web/CHANGELOG.md b/frontend/micro-ui/web/CHANGELOG.md deleted file mode 100644 index 826105084e8..00000000000 --- a/frontend/micro-ui/web/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -# Changelog -All notable changes to this module will be documented in this file. - -## 0.1.0 - 2024-05-28 -#### Base Admin console web - 1. Helps in creating the Campaign and configure delivery rules - 2. Create Data: Validates and creates resource details of type facility,user and boundary. diff --git a/frontend/micro-ui/web/docker/Dockerfile b/frontend/micro-ui/web/docker/Dockerfile deleted file mode 100644 index 8e9b173bb85..00000000000 --- a/frontend/micro-ui/web/docker/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -# FROM egovio/alpine-node-builder-14:yarn AS build -FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=8168" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && ./install-deps.sh \ - && yarn install \ - && yarn build:webpack - -FROM nginx:mainline-alpine -#FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/digit-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/devDockerfile b/frontend/micro-ui/web/docker/devDockerfile deleted file mode 100644 index d7b1ba1870a..00000000000 --- a/frontend/micro-ui/web/docker/devDockerfile +++ /dev/null @@ -1,26 +0,0 @@ -#FROM egovio/alpine-node-builder-14:yarn AS build -FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=1792" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && node envs.js \ - && ./install-deps.sh \ - && yarn install \ - && yarn build - -#FROM nginx:mainline-alpine -FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/digit-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/masDockerfile b/frontend/micro-ui/web/docker/masDockerfile deleted file mode 100644 index 5d7cf45dd87..00000000000 --- a/frontend/micro-ui/web/docker/masDockerfile +++ /dev/null @@ -1,25 +0,0 @@ -#FROM egovio/alpine-node-builder-14:yarn AS build -FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=3792" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && node envs.js \ - && yarn install \ - && yarn build - -#FROM nginx:mainline-alpine -FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/digit-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/nginx.conf b/frontend/micro-ui/web/docker/nginx.conf deleted file mode 100644 index 4f532e4a6ed..00000000000 --- a/frontend/micro-ui/web/docker/nginx.conf +++ /dev/null @@ -1,12 +0,0 @@ -server -{ - listen 80; - underscores_in_headers on; - - location /digit-ui - { - root /var/web; - index index.html index.htm; - try_files $uri $uri/ /digit-ui/index.html; - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/envs.js b/frontend/micro-ui/web/envs.js deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frontend/micro-ui/web/install-deps.sh b/frontend/micro-ui/web/install-deps.sh deleted file mode 100755 index efaceaee20d..00000000000 --- a/frontend/micro-ui/web/install-deps.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -BRANCH="$(git branch --show-current)" - -echo "Main Branch: $BRANCH" - -INTERNALS="micro-ui-internals" - -cp $INTERNALS/example/src/UICustomizations.js src/Customisations - -cd $INTERNALS && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" - - -# yarn install diff --git a/frontend/micro-ui/web/micro-ui-internals/.gitignore b/frontend/micro-ui/web/micro-ui-internals/.gitignore deleted file mode 100644 index 1747c795d6f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/.gitignore +++ /dev/null @@ -1,143 +0,0 @@ -# Created by https://www.toptal.com/developers/gitignore/api/node,react -# Edit at https://www.toptal.com/developers/gitignore?templates=node,react - -### eGov ### -packages/css/example/index.css -package-lock.json -locales/ -build/ -packages/**/dist/ - -# yarn # -.yarn -.yarnrc.yml - -### Node ### -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test -.env*.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next - -# Nuxt.js build / generate output -.nuxt -dist -dist-storybook - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -### react ### -.DS_* -**/*.backup.* -**/*.back.* - -node_modules - -*.sublime* - -psd -thumb -sketch - -# vs code -.vscode/ - -# End of https://www.toptal.com/developers/gitignore/api/node,react \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/.prettierignore b/frontend/micro-ui/web/micro-ui-internals/.prettierignore deleted file mode 100644 index d54de016ef0..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/.prettierignore +++ /dev/null @@ -1,23 +0,0 @@ - -# See https://help.github.com/ignore-files/ for more about ignoring files. -# dependencies -node_modules -# builds -build -dist -.rpt2_cache -# dev -dev.css -index.css -index.compat.css -index.min.css -# misc -.DS_Store -.env -.env.local -.env.development.local -.env.test.local -.env.production.local -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json b/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json deleted file mode 100644 index b975008d6f8..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "printWidth": 150 -} diff --git a/frontend/micro-ui/web/micro-ui-internals/README.md b/frontend/micro-ui/web/micro-ui-internals/README.md deleted file mode 100644 index f23a1fcfe9c..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/README.md +++ /dev/null @@ -1,100 +0,0 @@ - -# workbench ui - -A React App built on top of DIGIT UI Core. - - -# DIGIT UI - -DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://www.digit.org for more details. - -This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries. - -Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications - -It is also used to manage the Localisation data present in the system (Localisation service) - - -## Run Locally - -Clone the project - -```bash - git clone https://github.com/egovernments/Digit-Core.git -``` - -Go to the Sub directory to run UI -```bash - cd into frontend/micro-ui/web/micro-ui-internals -``` - -Install dependencies - -```bash - yarn install -``` - -Add .env file -```bash - frontend/micro-ui/web/micro-ui-internals/example/.env -``` - -Start the server - -```bash - yarn start -``` - - -## Environment Variables - -To run this project, you will need to add the following environment variables to your .env file - -`REACT_APP_PROXY_API` :: `{{server url}}` - -`REACT_APP_GLOBAL` :: `{{server url}}` - -`REACT_APP_PROXY_ASSETS` :: `{{server url}}` - -`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}` - -`SKIP_PREFLIGHT_CHECK` :: `true` - -[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev) - -## Tech Stack - -**Libraries:** - -[React](https://react.dev/) - -[React Hook Form](https://www.react-hook-form.com/) - -[React Query](https://tanstack.com/query/v3/) - -[Tailwind CSS](https://tailwindcss.com/) - -[Webpack](https://webpack.js.org/) - -## License - -[MIT](https://choosealicense.com/licenses/mit/) - - -## Author - -- [@jagankumar-egov](https://www.github.com/jagankumar-egov) - - -## Documentation - -[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) - - -## Support - -For support, add the issues in https://github.com/egovernments/DIGIT-core/issues. - - -![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) - diff --git a/frontend/micro-ui/web/micro-ui-internals/clean.sh b/frontend/micro-ui/web/micro-ui-internals/clean.sh deleted file mode 100644 index 2235ef1c1d0..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/clean.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -BASEDIR="$( cd "$( dirname "$0" )" && pwd )" - -msg() { - echo -e "\n\n\033[32;32m$1\033[0m" -} - -msg "Cleaning root" -rm -rf node_modules - -msg "Cleaning css" -cd "$BASEDIR/packages/css" && rm -rf node_modules - -msg "Cleaning libraries" -cd "$BASEDIR/packages/libraries" && rm -rf node_modules - -msg "Cleaning react-components" -cd "$BASEDIR/packages/react-components" && rm -rf node_modules - -msg "Cleaning PGR module" -cd "$BASEDIR/packages/modules/pgr" && rm -rf node_modules - -msg "Cleaning FSM module" -cd "$BASEDIR/packages/modules/fsm" && rm -rf node_modules - -msg "Cleaning Core module" -cd "$BASEDIR/packages/modules/core" && rm -rf node_modules diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa b/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa deleted file mode 100644 index 73b42b7dfad..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa +++ /dev/null @@ -1,7 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://health-qa.digit.org -REACT_APP_PROXY_ASSETS=https://health-qa.digit.org -REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCM.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod deleted file mode 100644 index 2d02707d7eb..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod +++ /dev/null @@ -1,7 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://salama.digit.org -REACT_APP_PROXY_ASSETS=https://salama.digit.org -REACT_APP_GLOBAL=https://moz-health-prd.s3.af-south-1.amazonaws.com/globalConfig.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat deleted file mode 100644 index bedf28a95b1..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat +++ /dev/null @@ -1,7 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://moz-health-uat.digit.org -REACT_APP_PROXY_ASSETS=https://moz-health-uat.digit.org -REACT_APP_GLOBAL=https://moz-health-uat.s3.ap-south-1.amazonaws.com/globalConfig.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev b/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev deleted file mode 100644 index 81fd56e040a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev +++ /dev/null @@ -1,9 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://unified-dev.digit.org -REACT_APP_PROXY_ASSETS=https://unified-dev.digit.org -REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsMicroplan.js -REACT_APP_CONTEXT=works -WORKBENCH=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCMMZ.js \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/example/package.json b/frontend/micro-ui/web/micro-ui-internals/example/package.json deleted file mode 100644 index 2d8c8857b45..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "@egovernments/digit-ui-example", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "private": true, - "homepage": "digit-ui", - "scripts": { - "start": "react-scripts start" - }, - "devDependencies": { - "@egovernments/digit-ui-libraries": "1.8.2-beta.1", - "@egovernments/digit-ui-module-workbench": "1.0.2-beta.3", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "@egovernments/digit-ui-module-core": "1.8.2-beta.2", - "@egovernments/digit-ui-module-utilities": "1.0.1-beta.30", - "@egovernments/digit-ui-react-components": "1.8.2-beta.6", - "@egovernments/digit-ui-module-hcmworkbench":"0.0.38", - "@egovernments/digit-ui-module-campaign-manager": "0.0.1", - "@egovernments/digit-ui-module-hcmmicroplanning": "0.0.1", - "http-proxy-middleware": "^1.0.5", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-i18next": "11.16.2", - "react-router-dom": "5.3.0", - "react-scripts": "^4.0.1" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html deleted file mode 100644 index 55ad3b5ca00..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - DIGIT - - - - - - - - - - - - - - - -
- - diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js deleted file mode 100644 index dff584d9ab2..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js +++ /dev/null @@ -1,789 +0,0 @@ -import { Link } from "react-router-dom"; -import _ from "lodash"; -import { useLocation, useHistory } from "react-router-dom"; -import { useParams } from "react-router-dom"; - -//create functions here based on module name set in mdms(eg->SearchProjectConfig) -//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] -// these functions will act as middlewares -var Digit = window.Digit || {}; - -const businessServiceMap = { - "muster roll": "MR", -}; - -const inboxModuleNameMap = { - "muster-roll-approval": "muster-roll-service", -}; - -function filterUniqueByKey(arr, key) { - const uniqueValues = new Set(); - const result = []; - - arr.forEach((obj) => { - const value = obj[key]; - if (!uniqueValues.has(value)) { - uniqueValues.add(value); - result.push(obj); - } - }); - - return result; -} - -const epochTimeForTomorrow12 = () => { - const now = new Date(); - - // Create a new Date object for tomorrow at 12:00 PM - const tomorrowNoon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 12, 0, 0, 0); - - // Format the date as "YYYY-MM-DD" - const year = tomorrowNoon.getFullYear(); - const month = String(tomorrowNoon.getMonth() + 1).padStart(2, "0"); // Months are 0-indexed - const day = String(tomorrowNoon.getDate()).padStart(2, "0"); - - return Digit.Utils.date.convertDateToEpoch(`${year}-${month}-${day}`); -}; - -function cleanObject(obj) { - for (const key in obj) { - if (Object.hasOwn(obj, key)) { - if (Array.isArray(obj[key])) { - if (obj[key].length === 0) { - delete obj[key]; - } - } else if ( - obj[key] === undefined || - obj[key] === null || - obj[key] === false || - obj[key] === "" || // Check for empty string - (typeof obj[key] === "object" && Object.keys(obj[key]).length === 0) - ) { - delete obj[key]; - } - } - } - return obj; -} - -export const UICustomizations = { - businessServiceMap, - updatePayload: (applicationDetails, data, action, businessService) => { - if (businessService === businessServiceMap.estimate) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - estimate: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap.contract) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - contract: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["muster roll"]) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - musterRoll: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["works.purchase"]) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - const additionalFieldsToSet = { - projectId: applicationDetails.additionalDetails.projectId, - invoiceDate: applicationDetails.billDate, - invoiceNumber: applicationDetails.referenceId.split("_")?.[1], - contractNumber: applicationDetails.referenceId.split("_")?.[0], - documents: applicationDetails.additionalDetails.documents, - }; - return { - bill: { ...applicationDetails, ...additionalFieldsToSet }, - workflow, - }; - } - }, - enableModalSubmit: (businessService, action, setModalSubmit, data) => { - if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") { - setModalSubmit(data?.acceptTerms); - } - }, - enableHrmsSearch: (businessService, action) => { - if (businessService === businessServiceMap.estimate) { - return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); - } - if (businessService === businessServiceMap.contract) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - if (businessService === businessServiceMap?.["muster roll"]) { - return action.action.includes("VERIFY"); - } - if (businessService === businessServiceMap?.["works.purchase"]) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - return false; - }, - getBusinessService: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return businessServiceMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return businessServiceMap?.contract; - } else if (moduleCode?.includes("muster roll")) { - return businessServiceMap?.["muster roll"]; - } else if (moduleCode?.includes("works.purchase")) { - return businessServiceMap?.["works.purchase"]; - } else if (moduleCode?.includes("works.wages")) { - return businessServiceMap?.["works.wages"]; - } else if (moduleCode?.includes("works.supervision")) { - return businessServiceMap?.["works.supervision"]; - } else { - return businessServiceMap; - } - }, - getInboxModuleName: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return inboxModuleNameMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return inboxModuleNameMap?.contracts; - } else if (moduleCode?.includes("attendence")) { - return inboxModuleNameMap?.attendencemgmt; - } else { - return inboxModuleNameMap; - } - }, - - AttendanceInboxConfig: { - preProcess: (data) => { - //set tenantId - data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId(); - data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - - const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim(); - if (musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber; - - const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim(); - if (attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName; - - // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side) - const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee); - delete data.body.inbox.moduleSearchCriteria.assignee; - if (assignee?.code === "ASSIGNED_TO_ME") { - data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid; - } - - //cloning locality and workflow states to format them - // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []); - - let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null); - delete data.body.inbox.moduleSearchCriteria.orgId; - if (selectedOrg) { - data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber; - } - - // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null); - // delete data.body.inbox.moduleSearchCriteria.ward; - // if(selectedWard) { - // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code; - // } - - let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []); - let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []); - // delete data.body.inbox.moduleSearchCriteria.locality; - delete data.body.inbox.moduleSearchCriteria.state; - delete data.body.inbox.moduleSearchCriteria.ward; - - // locality = locality?.map((row) => row?.code); - states = Object.keys(states)?.filter((key) => states[key]); - ward = ward?.map((row) => row?.code); - - // //adding formatted data to these keys - // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality; - if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states; - if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward; - const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {}); - if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code; - - //adding tenantId to moduleSearchCriteria - data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - - //setting limit and offset becoz somehow they are not getting set in muster inbox - data.body.inbox.limit = data.state.tableForm.limit; - data.body.inbox.offset = data.state.tableForm.offset; - delete data.state; - return data; - }, - postProcess: (responseArray, uiConfig) => { - const statusOptions = responseArray?.statusMap - ?.filter((item) => item.applicationstatus) - ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` })); - if (uiConfig?.type === "filter") { - let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus"); - if (fieldConfig.length) { - fieldConfig[0].populators.options = statusOptions; - } - } - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "ATM_MUSTER_ROLL_ID") { - return ( - - - {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} - - - ); - } - if (key === "ATM_ATTENDANCE_WEEK") { - const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate( - value?.endDate, - "dd/MM/yyyy" - )}`; - return
{week}
; - } - if (key === "ATM_NO_OF_INDIVIDUALS") { - return
{value?.length}
; - } - if (key === "ATM_AMOUNT_IN_RS") { - return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")}; - } - if (key === "ATM_SLA") { - return parseInt(value) > 0 ? ( - {t(value) || ""} - ) : ( - {t(value) || ""} - ); - } - if (key === "COMMON_WORKFLOW_STATES") { - return {t(`WF_MUSTOR_${value}`)}; - } - //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default - return {t(`CASE_NOT_HANDLED`)}; - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "ATM_MUSTER_ROLL_ID") - link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`; - }); - return link; - }, - populateReqCriteria: () => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - return { - url: "/org-services/organisation/v1/_search", - params: { limit: 50, offset: 0 }, - body: { - SearchCriteria: { - tenantId: tenantId, - functions: { - type: "CBO", - }, - }, - }, - config: { - enabled: true, - select: (data) => { - return data?.organisations; - }, - }, - }; - }, - }, - SearchWageSeekerConfig: { - customValidationCheck: (data) => { - //checking both to and from date are present - const { createdFrom, createdTo } = data; - if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - - return false; - }, - preProcess: (data) => { - data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() }; - - let requestBody = { ...data.body.Individual }; - const pathConfig = { - name: "name.givenName", - }; - const dateConfig = { - createdFrom: "daystart", - createdTo: "dayend", - }; - const selectConfig = { - wardCode: "wardCode[0].code", - socialCategory: "socialCategory.code", - }; - const textConfig = ["name", "individualId"]; - let Individual = Object.keys(requestBody) - .map((key) => { - if (selectConfig[key]) { - requestBody[key] = _.get(requestBody, selectConfig[key], null); - } else if (typeof requestBody[key] == "object") { - requestBody[key] = requestBody[key]?.code; - } else if (textConfig?.includes(key)) { - requestBody[key] = requestBody[key]?.trim(); - } - return key; - }) - .filter((key) => requestBody[key]) - .reduce((acc, curr) => { - if (pathConfig[curr]) { - _.set(acc, pathConfig[curr], requestBody[curr]); - } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { - _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); - } else { - _.set(acc, curr, requestBody[curr]); - } - return acc; - }, {}); - - data.body.Individual = { ...Individual }; - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - //here we can add multiple conditions - //like if a cell is link then we return link - //first we can identify which column it belongs to then we can return relevant result - switch (key) { - case "MASTERS_WAGESEEKER_ID": - return ( - - - {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} - - - ); - - case "MASTERS_SOCIAL_CATEGORY": - return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); - - case "CORE_COMMON_PROFILE_CITY": - return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); - - case "MASTERS_WARD": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - - case "MASTERS_LOCALITY": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - default: - return t("ES_COMMON_NA"); - } - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "MASTERS_WAGESEEKER_ID") - link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; - }); - return link; - }, - additionalValidations: (type, data, keys) => { - if (type === "date") { - return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; - } - }, - }, - SearchDefaultConfig: { - customValidationCheck: (data) => { - //checking both to and from date are present - const { createdFrom, createdTo } = data; - if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - - return false; - }, - preProcess: (data) => { - const location = useLocation(); - data.params = { ...data.params }; - const { masterName } = useParams(); - - const searchParams = new URLSearchParams(location.search); - const paths = { - SearchProjectConfig: { - basePath: "Projects", - pathConfig: { - // id: "id[0]", - tenantId: "tenantId", - }, - dateConfig: { - endDate: "dayend", - startDate: "daystart", - }, - selectConfig: {}, - textConfig: ["id", "tenantId", "name", "projectNumber", "projectSubType", "projectType"], - }, - SearchProductConfig: { - basePath: "Product", - pathConfig: { - id: "id[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: ["id", "manufacturer", "name", "type"], - }, - SearchHouseholdConfig: { - basePath: "Household", - pathConfig: { - id: "id[0]", - clientReferenceId: "clientReferenceId[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: ["boundaryCode", "clientReferenceId", "id"], - }, - SearchProductVariantConfig: { - basePath: "ProductVariant", - pathConfig: { - id: "id[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: ["productId", "sku", "variation"], - }, - SearchProjectBeneficiaryConfig: { - basePath: "ProjectBeneficiary", - pathConfig: { - id: "id[0]", - clientReferenceId: "clientReferenceId[0]", - }, - dateConfig: { - dateOfRegistration: "daystart", - }, - selectConfig: {}, - textConfig: ["beneficiaryId", "projectId"], - }, - SearchProjectStaffConfig: { - basePath: "ProjectStaff", - pathConfig: { - id: "id[0]", - }, - dateConfig: { - startDate: "daystart", - endDate: "dayend", - }, - selectConfig: {}, - textConfig: ["projectId", "userId"], - }, - SearchProjectResourceConfig: { - basePath: "ProjectResource", - pathConfig: { - id: "id[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: [], - }, - SearchProjectTaskConfig: { - basePath: "Task", - pathConfig: { - id: "id[0]", - clientReferenceId: "clientReferenceId[0]", - }, - dateConfig: { - plannedEndDate: "dayend", - plannedStartDate: "daystart", - actualEndDate: "dayend", - actualStartDate: "daystart", - }, - selectConfig: {}, - textConfig: ["projectId", "localityCode", "projectBeneficiaryId", "status"], - }, - SearchFacilityConfig: { - basePath: "Facility", - pathConfig: { - id: "id[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: ["faciltyUsage", "localityCode", "storageCapacity", "id"], - }, - SearchProjectFacilityConfig: { - basePath: "ProjectFacility", - pathConfig: { - id: "id[0]", - projectId: "projectId[0]", - facilityId: "facilityId[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: [], - }, - }; - - const id = searchParams.get("config") || masterName; - - if (!paths || !paths?.[id]) { - return data; - } - let requestBody = { ...data.body[paths[id]?.basePath] }; - const pathConfig = paths[id]?.pathConfig; - const dateConfig = paths[id]?.dateConfig; - const selectConfig = paths[id]?.selectConfig; - const textConfig = paths[id]?.textConfig; - - if (paths[id].basePath == "Projects") { - data.state.searchForm = { ...data.state.searchForm, tenantId: "mz" }; - } - let Product = Object.keys(requestBody) - .map((key) => { - if (selectConfig[key]) { - requestBody[key] = _.get(requestBody, selectConfig[key], null); - } else if (typeof requestBody[key] == "object") { - requestBody[key] = requestBody[key]?.code; - } else if (textConfig?.includes(key)) { - requestBody[key] = requestBody[key]?.trim(); - } - return key; - }) - .filter((key) => requestBody[key]) - .reduce((acc, curr) => { - if (pathConfig[curr]) { - _.set(acc, pathConfig[curr], requestBody[curr]); - } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { - _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); - } else { - _.set(acc, curr, requestBody[curr]); - } - return acc; - }, {}); - - if (paths[id].basePath == "Projects") { - data.body[paths[id].basePath] = [{ ...Product }]; - } else data.body[paths[id].basePath] = { ...Product }; - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - //here we can add multiple conditions - //like if a cell is link then we return link - //first we can identify which column it belongs to then we can return relevant result - switch (key) { - case "ID": - return ( - - - - ); - - case "MASTERS_SOCIAL_CATEGORY": - return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); - - case "CORE_COMMON_PROFILE_CITY": - return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); - - case "MASTERS_WARD": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - - case "MASTERS_LOCALITY": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - default: - return t("ES_COMMON_NA"); - } - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "MASTERS_WAGESEEKER_ID") - link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; - }); - return link; - }, - additionalValidations: (type, data, keys) => { - if (type === "date") { - return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; - } - }, - }, - SearchCampaign: { - preProcess: (data, additionalDetails) => { - const { campaignName = "", endDate = "", projectType = "", startDate = "" } = data?.state?.searchForm || {}; - data.body.CampaignDetails = {}; - data.body.CampaignDetails.pagination = data?.state?.tableForm; - data.body.CampaignDetails.tenantId = Digit.ULBService.getCurrentTenantId(); - // data.body.CampaignDetails.boundaryCode = boundaryCode; - data.body.CampaignDetails.createdBy = Digit.UserService.getUser().info.uuid; - data.body.CampaignDetails.campaignName = campaignName; - data.body.CampaignDetails.status = ["drafted"]; - if (startDate) { - data.body.CampaignDetails.startDate = Digit.Utils.date.convertDateToEpoch(startDate); - } else { - data.body.CampaignDetails.startDate = epochTimeForTomorrow12(); - } - if (endDate) { - data.body.CampaignDetails.endDate = Digit.Utils.date.convertDateToEpoch(endDate); - } - data.body.CampaignDetails.projectType = projectType?.[0]?.code; - - cleanObject(data.body.CampaignDetails); - - return data; - }, - populateProjectType: () => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - - return { - url: "/egov-mdms-service/v1/_search", - params: { tenantId }, - body: { - MdmsCriteria: { - tenantId, - moduleDetails: [ - { - moduleName: "HCM-PROJECT-TYPES", - masterDetails: [ - { - name: "projectTypes", - }, - ], - }, - ], - }, - }, - changeQueryName: "projectType", - config: { - enabled: true, - select: (data) => { - const dropdownData = filterUniqueByKey(data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes, "code").map((row) => { - return { - ...row, - i18nKey: Digit.Utils.locale.getTransformedLocale(`CAMPAIGN_TYPE_${row.code}`), - }; - }); - return dropdownData; - }, - }, - }; - }, - customValidationCheck: (data) => { - //checking if both to and from date are present then they should be startDate<=endDate - const { startDate, endDate } = data; - const startDateEpoch = Digit.Utils.date.convertDateToEpoch(startDate); - const endDateEpoch = Digit.Utils.date.convertDateToEpoch(endDate); - - if (startDate && endDate && startDateEpoch > endDateEpoch) { - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - } - return false; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "CAMPAIGN_DATE") { - return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.endDate)}`; - } - }, - }, - SearchMicroplan: { - preProcess: (data, additionalDetails) => { - const { name, status } = data?.state?.searchForm || {}; - - data.body.PlanConfigurationSearchCriteria = {}; - data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit; - // data.body.PlanConfigurationSearchCriteria.limit = 10 - data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset; - data.body.PlanConfigurationSearchCriteria.name = name; - data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid; - // delete data.body.PlanConfigurationSearchCriteria.pagination - data.body.PlanConfigurationSearchCriteria.status = status?.status; - cleanObject(data.body.PlanConfigurationSearchCriteria); - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "CAMPAIGN_DATE") { - return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.CampaignDetails?.endDate)}`; - } - }, - }, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/index.js b/frontend/micro-ui/web/micro-ui-internals/example/src/index.js deleted file mode 100644 index c186da539bd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/src/index.js +++ /dev/null @@ -1,84 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; - -import { initLibraries } from "@egovernments/digit-ui-libraries"; -// import { paymentConfigs, PaymentLinks, PaymentModule } from "@egovernments/digit-ui-module-common"; -import { DigitUI } from "@egovernments/digit-ui-module-core"; -import "@egovernments/digit-ui-css/example/index.css"; - -import { UICustomizations } from "./UICustomizations"; -import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager" -import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; -import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; -import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; -import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; - -var Digit = window.Digit || {}; - -const enabledModules = [ - "DSS", - "HRMS", - "Workbench", - "HCMWORKBENCH", - "Campaign", - // "Engagement", "NDSS","QuickPayLinks", "Payment", - "Utilities", - "Microplanning" - //added to check fsm - // "FSM" -]; - -const initTokens = (stateCode) => { - const userType = window.sessionStorage.getItem("userType") || process.env.REACT_APP_USER_TYPE || "CITIZEN"; - const token = window.localStorage.getItem("token") || process.env[`REACT_APP_${userType}_TOKEN`]; - - const citizenInfo = window.localStorage.getItem("Citizen.user-info"); - - const citizenTenantId = window.localStorage.getItem("Citizen.tenant-id") || stateCode; - - const employeeInfo = window.localStorage.getItem("Employee.user-info"); - const employeeTenantId = window.localStorage.getItem("Employee.tenant-id"); - - const userTypeInfo = userType === "CITIZEN" || userType === "QACT" ? "citizen" : "employee"; - window.Digit.SessionStorage.set("user_type", userTypeInfo); - window.Digit.SessionStorage.set("userType", userTypeInfo); - - if (userType !== "CITIZEN") { - window.Digit.SessionStorage.set("User", { access_token: token, info: userType !== "CITIZEN" ? JSON.parse(employeeInfo) : citizenInfo }); - } else { - // if (!window.Digit.SessionStorage.get("User")?.extraRoleInfo) window.Digit.SessionStorage.set("User", { access_token: token, info: citizenInfo }); - } - - window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); - - if (employeeTenantId && employeeTenantId.length) window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); -}; - -const initDigitUI = () => { - window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH") || "digit-ui"; - window.Digit.Customizations = { - commonUiConfig: UICustomizations - }; - window?.Digit.ComponentRegistryService.setupRegistry({ - // PaymentModule, - // ...paymentConfigs, - // PaymentLinks, - }); - initUtilitiesComponents(); - initWorkbenchComponents(); - initWorkbenchHCMComponents(); - initCampaignComponents(); - initMicroplanningComponents(); - - const moduleReducers = (initData) => initData; - - - const stateCode = window?.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || "pb"; - initTokens(stateCode); - - ReactDOM.render(, document.getElementById("root")); -}; - -initLibraries().then(() => { - initDigitUI(); -}); diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js b/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js deleted file mode 100644 index 9fbb1258ba9..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js +++ /dev/null @@ -1,101 +0,0 @@ -const { createProxyMiddleware } = require("http-proxy-middleware"); - -const createProxy = createProxyMiddleware({ - //target: process.env.REACT_APP_PROXY_API || "https://uat.digit.org", - // target: process.env.REACT_APP_PROXY_API || "https://qa.digit.org", - target: process.env.REACT_APP_PROXY_API || "https://works-dev.digit.org", - changeOrigin: true, - secure: false, -}); -const assetsProxy = createProxyMiddleware({ - target: process.env.REACT_APP_PROXY_ASSETS || "https://works-dev.digit.org", - changeOrigin: true, - secure: false, -}); -const mdmsProxy = createProxyMiddleware({ - target: process.env.REACT_APP_PROXY_ASSETS || "http://localhost:8080", - changeOrigin: true, - secure: false, -}); -module.exports = function (app) { - ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); - [ - "/access/v1/actions/mdms", - "/egov-mdms-service", - "/mdms-v2", - "/egov-idgen", - "/egov-location", - "/localization", - "/egov-workflow-v2", - "/pgr-services", - "/filestore", - "/egov-hrms", - "/user-otp", - "/user", - "/fsm", - "/billing-service", - "/collection-services", - "/pdf-service", - "/pg-service", - "/vehicle", - "/vendor", - "/property-services", - "/fsm-calculator/v1/billingSlab/_search", - "/pt-calculator-v2", - "/dashboard-analytics", - "/echallan-services", - "/egov-searcher/bill-genie/mcollectbills/_get", - "/egov-searcher/bill-genie/billswithaddranduser/_get", - "/egov-searcher/bill-genie/waterbills/_get", - "/egov-searcher/bill-genie/seweragebills/_get", - "/egov-pdf/download/UC/mcollect-challan", - "/egov-hrms/employees/_count", - "/tl-services/v1/_create", - "/tl-services/v1/_search", - "/egov-url-shortening/shortener", - "/inbox/v1/_search", - "/inbox/v2/_search", - "/tl-services", - "/tl-calculator", - "/org-services", - "/edcr", - "/bpa-services", - "/noc-services", - "/egov-user-event", - "/egov-document-uploader", - "/egov-pdf", - "/egov-survey-services", - "/ws-services", - "/sw-services", - "/ws-calculator", - "/sw-calculator/", - "/egov-searcher", - "/report", - "/inbox/v1/dss/_search", - "/loi-service", - "/project/v1/", - "/estimate-service", - "/loi-service", - "/works-inbox-service/v2/_search", - "/egov-pdf/download/WORKSESTIMATE/estimatepdf", - "/muster-roll", - "/individual", - "/mdms-v2", - "/hcm-moz-impl", - "/project", - "/project/staff/v1/_search", - "/project/v1/_search", - "/facility/v1/_search", - "/product/v1/_search", - "/product/variant/v1/_search", - "/hcm-bff/bulk/_transform", - "/hcm-bff/hcm/_processmicroplan", - "/health-hrms", - "/project-factory", - "/boundary-service", - "/product", - "/plan-service", - ].forEach((location) => app.use(location, createProxy)); - ["/pb-egov-assets"].forEach((location) => app.use(location, assetsProxy)); - ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/package.json b/frontend/micro-ui/web/micro-ui-internals/package.json deleted file mode 100644 index d15c627d3ab..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "egovernments", - "version": "1.0.0", - "main": "index.js", - "workspaces": [ - "example", - "packages/css", - "packages/modules/*" - ], - "author": "JaganKumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "scripts": { - "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", - "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", - "start:dev": "run-p dev:**", - "start:script": "./scripts/create.sh", - "dev:css": "cd packages/css && yarn start", - "publish:css": "cd packages/css && yarn && npm publish --tag workbench-1.0", - "dev:example": "cd example && yarn start", - "dev:campaign": "cd packages/modules/campaign-manager && yarn start", - "dev:hcmmicroplan": "cd packages/modules/hcm-microplanning && yarn start", - "build": "run-p build:**", - "build:campaign": "cd packages/modules/campaign-manager && yarn build", - "build:hcmmicroplan": "cd packages/modules/hcm-microplanning && yarn build", - "deploy:jenkins": "./scripts/jenkins.sh", - "clean": "rm -rf node_modules" - }, - "resolutions": { - "**/@babel/runtime": "7.20.1", - "**/babel-preset-react-app": "10.0.0" - }, - "devDependencies": { - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "husky": {}, - "lint-staged": { - "*.{js,css,md}": "prettier --write" - }, - "dependencies": { - "ajv": "8.12.0", - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "@egovernments/digit-ui-react-components": "1.8.2-beta.6", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0" - } -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md b/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md deleted file mode 100644 index 6efe08ae5c5..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md +++ /dev/null @@ -1,62 +0,0 @@ - - -# digit-ui-css - -## Install - -```bash -npm install --save @egovernments/digit-ui-css -``` - -## Limitation - -```bash -This Package is more specific to DIGIT-UI's can be used across mission's -It is the base css for all Digit UI's -``` - -## Usage - -After adding the dependency make sure you have this dependency in - -```bash -frontend/micro-ui/web/package.json -``` - -```json -"@egovernments/digit-ui-css":"^1.5.0", -``` - -then navigate to App.js - -```bash -frontend/micro-ui/web/public/index.html -``` - -```jsx -/** add this import **/ - - - -``` -### Changelog - -```bash -1.0.7-campaign some css fixes in attribute -1.0.5-campaign some css fixes in previous button -1.0.4-campaign updated styling for create campaign screens -1.0.2-campaign update Styling added for delivery rule screen -1.0.1-campaign Styling added for delivery rule screen -1.0.0-campaign Base version - -``` -## Contributors - -[jagankumar-egov] [nipunarora-eGov] - -### Published from DIGIT Frontend -DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/develop) - -## License - -MIT © [jagankumar-egov](https://github.com/jagankumar-egov) diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js deleted file mode 100644 index 5d1a705494a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js +++ /dev/null @@ -1,71 +0,0 @@ -const fs = require("fs"); -const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync("package.json")); - -const headerString = ` -@charset "UTF-8"; -/*! - * ${name} - ${version} - * - * Copyright (c) ${new Date().getFullYear()} ${author} - * - */ - `; -const { series, src, dest, watch, task } = require("gulp"); -const header = require("postcss-header"); - -const clean = require("gulp-clean"); -const postcss = require("gulp-postcss"); -const sass = require('gulp-sass'); - -const postcssPresetEnv = require("postcss-preset-env"); -const cleanCSS = require("gulp-clean-css"); -const rename = require("gulp-rename"); -const livereload = require("gulp-livereload"); - -let output = "./example"; -if (process.env.NODE_ENV === "production") { - output = "./dist"; -} - -function cleanStyles() { - return src(`${output}/*.css`, { read: false }).pipe(clean()); -} - -function styles() { - const plugins = [ - require("postcss-import"), - require("tailwindcss"), - postcssPresetEnv({ stage: 2, autoprefixer: { cascade: false }, features: { "custom-properties": true } }), - require("autoprefixer"), - require("cssnano"), - header({ header: headerString }), - ]; - return src("src/index.scss").pipe(postcss(plugins)).pipe(sass()).pipe(dest(output)); -} - -function minify() { - return src(`${output}/index.css`).pipe(cleanCSS()).pipe(rename(`index.min.css`)).pipe(dest(output)); -} - -function stylesLive() { - styles().pipe(livereload({ start: true })); -} - -function livereloadStyles() { - livereload.listen(); - watch("src/**/*.scss", series(stylesLive)); -} - -exports.styles = styles; -exports.default = series(styles); -exports.watch = livereloadStyles; -if (process.env.NODE_ENV === "production") { - exports.build = series(cleanStyles, styles, minify); -} else { - exports.build = series(styles, livereloadStyles); -} - -// gulp.task("watch:styles", function () { -// livereload.listen(); -// gulp.watch("**/*.scss", ["styles"]); -// }); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json deleted file mode 100644 index 5f503a9ebf5..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "@egovernments/digit-ui-css", - "version": "1.0.56-campaign", - "license": "MIT", - "main": "dist/index.css", - "author": "Jagankumar ", - "engines": { - "node": ">=14" - }, - "cssConfig": { - "prefix": "" - }, - "scripts": { - "start": "gulp build", - "build:prod": "NODE_ENV=production gulp build", - "prepublish": "yarn build:prod", - "deploy": "gulp && cp -R svg example && cp -R img example && gh-pages -d example" - }, - "browserslist": [ - "> 3%", - "last 2 versions" - ], - "style": "./dist/index.css", - "dependencies": { - "node-sass": "4.14.1", - "normalize.css": "8.0.1", - "postcss-scss": "3.0.5", - "tailwindcss": "1.9.6" - }, - "devDependencies": { - "autoprefixer": "10.4.14", - "cssnano": "4.1.11", - "gh-pages": "3.2.3", - "gulp": "4.0.2", - "gulp-clean": "0.4.0", - "gulp-clean-css": "4.3.0", - "gulp-livereload": "4.0.2", - "gulp-postcss": "9.0.1", - "gulp-rename": "2.0.0", - "gulp-sass": "4.1.1", - "postcss": "8.4.26", - "postcss-cli": "8.3.1", - "postcss-header": "2.0.0", - "postcss-import": "12.0.1", - "postcss-prefixer": "2.1.3", - "postcss-preset-env": "6.7.1", - "postcss-scss": "3.0.5", - "sass": "^1.26.11" - }, - "files": [ - "dist/index.min.css", - "dist/index.css", - "svg/**/*.svg", - "img/**/*.png", - "src/**/*.scss", - "src/**/*.css" - ], - "keywords": [ - "digit", - "egov", - "dpg", - "digit-ui", - "css" - ] -} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js deleted file mode 100644 index 18485de221e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js +++ /dev/null @@ -1,55 +0,0 @@ -const postcssPresetEnv = require("postcss-preset-env"); - -module.exports = { - parser: require("postcss-scss"), - plugins: [ - require("postcss-import"), - require("postcss-nested").default, - require("tailwindcss"), - require("postcss-preset-env"), - require("autoprefixer"), - // require("cssnano"), - ], -}; - -// const fs = require('fs'); -// const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync('package.json')); - -// const header = ` -// @charset "UTF-8"; -// /*! -// * ${name} - ${version} -// * -// * Copyright (c) ${new Date().getFullYear()} ${author.name} -// */ -// `; - -// module.exports = (ctx) => { -// const prefix = ctx.env === 'compat' ? '' : cssConfig.prefix; -// const devMessage = `🎉🎉🎉🎉 \n${name} ${ctx.env} build was compiled sucessfully! \n`; - - -// return { -// map: ctx.options.map, -// parser: ctx.options.parser, -// plugins: { -// 'postcss-import': { root: ctx.file.dirname }, -// 'postcss-prefixer': { -// prefix, -// ignore: [/\[class\*=.*\]/], -// }, -// 'postcss-preset-env': { -// autoprefixer: { -// cascade: false, -// }, -// features: { -// 'custom-properties': true, -// }, -// }, -// cssnano: ctx.env === 'production' || ctx.env === 'compat' ? {} : false, -// 'postcss-header': { -// header, -// }, -// }, -// }; -// }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss deleted file mode 100644 index f01756f1e7d..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss +++ /dev/null @@ -1,363 +0,0 @@ -.microplanning { - .upload { - display: flex; - width: 100%; - justify-content: space-between; - margin-top: 1.25rem; - } - - .upload-section-option { - width: 12.5rem; - min-height: 32rem; - background-color: #ffffff; - border-top-left-radius: 0.5rem; - border-bottom-left-radius: 0.5rem; - padding: 0.625rem; - box-shadow: 0px 1px 2px 0px #00000029; - } - - .upload-section-options-active { - min-height: 3.7rem; - display: flex; - align-items: center; - border-bottom: 1px rgba(214, 213, 212, 1) solid; - cursor: pointer; - border-right: 0.3rem solid rgba(244, 119, 56, 1); - background-color: rgba(244, 119, 56, 0.12); - - p { - color: rgba(80, 90, 95, 1); - font-weight: 400; - font-size: 16px; - } - } - - .upload-section-options-inactive { - min-height: 3.7rem; - display: flex; - align-items: center; - border-bottom: 1px rgba(214, 213, 212, 1) solid; - cursor: pointer; - border-right: none; - background-color: rgba(255, 255, 255, 1); - - p { - color: rgba(80, 90, 95, 1); - font-weight: 400; - font-size: 16px; - } - } - - .upload-component { - width: 80%; - height: min-content; - border-radius: 0.25rem; - padding: 1.5rem; - background-color: rgba(255, 255, 255, 1); - margin: 0; - margin-right: 0.3rem; - padding-bottom: 0.625rem; - } - - .upload-component-active { - display: flex; - flex-direction: column; - margin-bottom: 0; - - .greyedout-name { - color: rgba(177, 180, 182, 1); - margin: 0 0.625rem; - font-size: 1.25rem; - padding-top: 0px; - font-weight: 500; - } - - h2 { - margin-top: 0.625rem; - font-size: 2.5rem; - margin: 0.625rem 0; - font-weight: 700; - } - - p { - margin: 0.625rem 0; - padding-top: 0.625; - font-size: 1rem; - margin-top: 0.625rem; - font-weight: 400; - } - } - - .upload-component-inactive { - display: none; - } - - .upload-option-container { - display: flex; - align-items: center; - justify-content: center; - padding: 1.25rem 0; - flex-wrap: wrap; - - .upload-option-container-selected { - border: 2px rgba(244, 119, 56, 1) solid; - color: rgba(244, 119, 56, 1); - } - } - - .upload-option { - border-radius: 0.25rem; - border: 0.0625rem rgba(214, 213, 212, 1) solid; - min-width: 12.5rem; - min-height: 8.75rem; - box-shadow: 0 0.0625rem rgba(0, 0, 0, 0.16); - padding: 0.625rem 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - justify-items: center; - margin: 0 1.25rem; - cursor: pointer; - - &:hover { - border: 2px rgba(244, 119, 56, 1) solid; - } - - p { - margin-top: 0.625rem; - } - - .upload-option-selected { - border: 0.125rem rgba(244, 119, 56, 1) solid; - color: rgba(244, 119, 56, 1); - } - - .select-button { - justify-self: end; - border: 1px solid rgba(244, 119, 56, 1); - background-color: rgba(255, 255, 255, 1); - width: 11rem; - height: 2.5rem; - padding: 0.6rem 0.5rem; - color: rgba(244, 119, 56, 1); - font-size: 1rem; - font-weight: 600; - } - - .selected-button { - justify-self: end; - border: 1px solid rgba(244, 119, 56, 1); - background-color: rgba(244, 119, 56, 1); - width: 11rem; - height: 2.5rem; - padding: 0.6rem 0.5rem; - color: rgb(255, 255, 255); - font-size: 1rem; - font-weight: 600; - } - } - - .modal-header { - width: 30rem; - font-weight: 700; - font-size: 1.5rem; - padding-left: 1rem; - margin-bottom: 0; - display: flex; - flex-wrap: wrap; - overflow: hidden; - } - - .modal-body { - overflow: hidden; - padding-left: 1rem; - padding-right: 1rem; - margin-bottom: 1rem; - margin-right: 1rem; - - p { - font-weight: 400; - font-size: 1rem; - } - } - - .upload-file { - min-width: 90%; - min-height: 10rem; - padding-top: 0.625; - border: 1px rgba(214, 213, 212, 1) dotted; - margin: 1rem 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - background-color: rgba(250, 250, 250, 255); - } - - .uploaded-file { - border: 1px solid rgba(214, 213, 212, 1); - min-height: 4.75rem; - background-color: rgb(256, 252, 252); - display: flex !important; - flex-direction: row; - justify-content: space-between; - align-items: center; - margin-top: 0.625rem; - padding: 0 0.625rem; - flex-wrap: wrap; - - .uploaded-file-details { - display: flex; - flex-direction: row; - align-items: center; - flex-wrap: wrap; - padding: 1rem 0; - - p { - padding: 0; - margin: 0; - height: min-content; - font-weight: 700; - font-size: 1.5rem; - color: rgba(80, 90, 95, 1); - text-align: start; - } - } - - .uploaded-file-operations { - display: flex !important; - flex-direction: row; - align-items: center; - justify-items: end; - flex-wrap: wrap; - .button { - display: flex !important; - flex-direction: row; - align-items: center !important; - justify-content: center; - margin-left: 1rem; - min-width: 9rem; - height: 2.5rem; - border: 1px rgba(244, 119, 56, 1) solid; - background-color: white; - cursor: pointer; - } - - p { - padding: 0; - margin: 0; - color: rgba(244, 119, 56, 1); - font-weight: 600; - font-size: 1rem; - } - - .deletebutton { - background-color: rgb(255, 255, 255, 0); - border: none; - } - } - } - - .loader-container { - display: flex; - justify-content: center; - align-items: center; - height: 100%; - width: 100%; - display: flex; - flex-direction: column; - background-color: rgba(0, 0, 0, 0.7); - position: fixed; - top: 0; - left: 0; - z-index: 99999; - - .loader { - border: 0.5rem solid rgb(255, 255, 255); - border-top: 0.5rem solid rgba(80, 76, 76, 0); - border-radius: 50%; - width: 3.125rem; - height: 3.125rem; - animation: spin 2s linear infinite; - } - - .loader-inner { - border: 1px solid rgb(255, 255, 255); - border-radius: 50%; - width: 100%; - height: 100%; - } - - .loader-text { - color: whitesmoke; - padding-top: 1.25rem; - } - } - - @keyframes spin { - 0% { - transform: rotate(0deg); - } - - 100% { - transform: rotate(360deg); - } - } - - .toast-container { - position: fixed; - width: 50%; - bottom: 1.25rem; - left: 50%; - transform: translateX(-50%); - color: #fff; - padding: 1rem; - z-index: 9999; - } - - .success { - background-color: rgba(0, 112, 60, 1); - } - - .toast-content { - display: flex; - align-items: center; - justify-content: space-between; - } - - .message { - margin-right: 0.6px; - } - - .close-button { - background: transparent; - border: none; - color: inherit; - cursor: pointer; - } - - .altrady-have-template-button { - display: flex !important; - justify-content: center; - font-weight: 600; - font-size: 1rem; - } - - .download-template-button { - display: flex !important; - justify-content: center; - - .icon { - display: flex; - align-items: center; - margin: 0; - padding: 0; - } - - p { - font-weight: 500; - font-size: 1rem; - } - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss deleted file mode 100644 index ff5ace2af3e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss +++ /dev/null @@ -1,13 +0,0 @@ -/*@import 'normalize.css';*/ - -/*@import url("https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@400;500;700&family=Roboto:wght@400;500;700&display=swap");*/ - -@import "tailwindcss/base"; - -@import "tailwindcss/components"; - -@import "tailwindcss/utilities"; - -@import "./components/microplanning.scss"; -@import "./pages/employee/index.scss"; -@import "./pages/employee/campaign.scss"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss deleted file mode 100644 index 5c6b56289d3..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss +++ /dev/null @@ -1,109 +0,0 @@ -@import url("../../index.scss"); -@import "../../typography.scss"; - -.summary-header { - @extend .typography.text-heading-l; - font-size: 2.25rem; -} -.date-field-container { - display: grid; - grid-template-columns: 20rem 20rem; - grid-gap: 1.5rem; - width: 70%; - padding-top: 0.3rem; - margin-top: 0rem; -} -.date-field { - display: grid; - grid-template-columns: 1fr 2fr; - align-items: start; -} -.campaign-type { - margin-right: 5rem; - padding-bottom: 1.2rem; - font-weight: bold; -} -.name-container { - margin-right: 4rem; - font-weight: bold; - text-wrap: nowrap; -} -.beneficiary-type { - margin-right: 5.4rem; - font-weight: bold; -} -.campaign-dates { - display: flex; - font-weight: bold; -} -.mandatory-date { - margin-top: 0.8rem; - margin-left: 0.5rem; - color: red !important; - font-size: 1rem; - font-weight: 700; -} -.description-type { - margin-top: 2rem; - margin-bottom: 2rem; -} -.name-description { - margin-top: 2rem; - margin-bottom: 2rem; -} -.dates-description { - margin-top: 1rem; - margin-bottom: 1rem; - padding-bottom: 1.2rem; -} -.selecting-boundary-div { - padding-top: 0.5rem; - .label-field-pair { - margin-bottom: 1.5rem; - } -} -.campaign-table { - border-collapse: collapse; - border-color: transparent; - border-width: 0rem 1.5rem; - tbody { - tr:hover { - background: rgba(#f47738, 0.12); - } - } -} -.info-points { - display: flex; - gap: 0.5rem; - margin-bottom: 0.5rem; -} -.infoClass{ - margin-bottom: 1.5rem -} -.headerWrapperClassName{ - display: none -} -.popup-close-svg{ - display: none; -} -.whoLogo{ - margin-top: -1rem; - margin-bottom: -1rem; -} - -.digit-popup-wrapper{ - &.popUpClass{ - width:45rem; - - .popUpFooter{ - .digit-popup-footer-buttons{ - margin-left: 0px; - width: 100%; - - button{ - flex:1; - } - } - } - } -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss deleted file mode 100644 index 74296abb568..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss +++ /dev/null @@ -1,331 +0,0 @@ -@import "../../typography.scss"; - -.campaign-cycle-container { - .campaign-tabs-container { - } - .sub-tab-container { - margin-top: 5px; - padding: 1.5rem; - .card-text { - margin-bottom: 0; - } - } - .add-resource-container { - background-color: #fafafa; - border: 1px solid #d6d5d4; - border-radius: 0.4rem; - padding: 1rem; - margin-right: 1.5rem; - margin-bottom: 1.5rem; - .card-text { - margin: 0; - font-weight: 700; - } - .header-container { - display: flex; - align-items: flex-end; - justify-content: space-between; - } - } - .delete-resource-icon { - cursor: pointer; - font-weight: 600; - font-size: 1rem; - color: theme(digitv2.lightTheme.primary); - display: flex; - gap: 0.5rem; - align-items: center; - } - .add-resource-label-field-container { - display: grid; - grid-template-columns: 2fr 1fr; - grid-gap: 2rem; - .options-card { - max-height: 10rem !important; - } - } - .popup-wrap { - .popup-module-main { - max-height: 707px; - overflow-y: auto; - width: 99%; - &::-webkit-scrollbar { - width: 0.5rem; - background: transparent; - } - &::-webkit-scrollbar-thumb { - background: #d6d5d4; /* Color of the scrollbar thumb */ - border-radius: 5px; /* Adjust the border-radius for rounded corners */ - height: 0.5rem; - } - } - .popup-module-action-bar { - .selector-button-primary { - padding: 0.6rem 2.5rem; - height: unset; - margin: 1.5rem; - background-color: theme(digitv2.lightTheme.primary); - } - } - } -} -.selector-button-primary { - background-color: theme(digitv2.lightTheme.primary); -} -.campaign-breadcrumb { - margin: 0; - margin-bottom: 1.5rem; - color: theme(digitv2.lightTheme.primary) !important; -} -.sc-jlZhew.dVtbRz { - overflow: hidden; -} -.campaign-popup-module { - margin: auto; - width: calc(100% - 5rem); -} -.campaign-bulk-upload { - display: flex; - justify-content: space-between; - margin-bottom: 1.5rem; - .campaign-download-template-btn { - font-weight: 700; - } -} -.bulk-info-text { - margin-bottom: 1.5rem; -} -.delete-and-download-button { - display: flex; - gap: 1.5rem; -} -.bulk-upload-file { - .uploaded-file-container { - margin: 0; - margin-bottom: 1.5rem; - } -} -.uploaded-file-container { - margin-left: 0rem; -} -.upload-drag-drop-container { - background-color: #fafafa; - border: 1.5px dashed #d6d5d4; - border-radius: 5px; - padding: 1rem 1rem 1rem 1rem; - display: flex; - align-items: center; - flex-direction: column; - - .drag-drop-text { - text-decoration: none; - - .browse-text { - text-decoration: none; - color: theme(digitv2.lightTheme.primary); - transition: color 0.3s; - } - - .browse-text:hover { - color: theme(digitv2.lightTheme.primary); - text-decoration: underline; - cursor: pointer; - } - } -} - -.upload-drag-drop-container { - margin-left: 0rem; - .drag-drop { - color: #b1b4b6; - } - .browse-text { - text-decoration: underline; - color: theme(digitv2.lightTheme.primary); - transition: color 0.3s; - } -} - -.campaign-counter-container { - padding: 1.5rem; - padding-bottom: 0.5rem; - .card-text { - margin-top: 0; - } - .label-field-pair { - margin-bottom: 1rem; - .card-label { - font-weight: 700; - } - } - .date-field-container { - display: grid; - grid-template-columns: 18.75rem 18.75rem; - grid-gap: 1.5rem; - width: 100%; - } - .PlusMinus { - width: 30%; - input { - width: 100%; - } - } -} - -.campaign-tab-head { - padding: 1rem; - width: 12.5rem; - height: 3rem; - border-radius: 10px 10px 0px 0px; - background-color: #ffffff; - outline: none; - box-sizing: border-box; - font-weight: 700; - font-size: 1rem; - font-family: "Roboto"; - color: #505a5f; - margin-bottom: -6px; - border: 1px solid #d6d5d4; - background-color: #fafafa; - &.active { - height: 3.375rem; - background-color: #ffffff; - outline: none; - font-weight: bold; - color: theme(digitv2.lightTheme.primary); - border: 1px solid theme(digitv2.lightTheme.primary); - border-bottom: 4px solid theme(digitv2.lightTheme.primary); - box-sizing: border-box; - font-size: 1.5rem; - } - :focus { - outline: none; - } -} -.campaign-sub-tab-head { - outline: none; - background-color: #ffffff; - color: theme(digitv2.lightTheme.primary); - border: 1px solid theme(digitv2.lightTheme.primary); - height: 2rem; - width: 9.188rem; - font-size: 1rem; - font-weight: 400; - &.active { - background-color: theme(digitv2.lightTheme.primary); - color: #ffffff; - font-weight: bold; - outline: none; - height: 2rem; - width: 9.188rem; - font-family: "Roboto"; - font-weight: 700; - font-size: 1rem; - } -} -.tab-content-header { - margin-top: 1.5rem; - margin-bottom: 1.5rem !important; -} - -.delivery-rule-container { - padding-top: 0; - .card-header { - .title { - margin: 0 !important; - } - font-size: 1.5rem !important; - margin: 0; - display: flex; - align-content: center; - justify-content: space-between; - } - .attribute-container { - border: 1px solid #d6d5d4; - background-color: #fafafa; - padding: 1rem; - padding-top: 0; - .add-attribute { - width: 74.5%; - justify-content: center; - h2 { - font-size: 1rem; - font-family: Roboto; - width: unset !important; - font-weight: 600; - } - } - } -} -.attribute-field-wrapper { - display: grid; - grid-template-columns: 1fr 1fr 1fr 1fr; - align-items: center; - gap: 2.5rem; - .label-field-pair { - flex-direction: column; - align-items: flex-start !important; - .card-label.card-label-smaller { - font-weight: 700; - } - .employee-select-wrap.form-field { - width: 100%; - } - .digit-employee-card-input { - margin-bottom: 0; - } - } - .options-card { - max-height: 10rem !important; - } - .card-label { - margin-bottom: 0.5rem; - } -} -.add-rule-btn { - margin: auto; - h2 { - font-family: Roboto; - font-size: 1rem; - font-weight: 600; - } -} -.add-product-btn { - h2 { - font-family: Roboto; - font-size: 1rem; - font-weight: 600; - } -} -.popup-wrap.campaign-product-wrapper { - .popup-module { - width: 70%; - padding-left: 1.5rem; - padding-bottom: 1.5rem; - .header-wrap { - font-size: 1.5rem; - font-weight: 700; - .header-content.popup-header-fix { - margin-top: 1.5rem; - } - } - } - .popup-module-action-bar { - margin-top: 1.5rem; - margin-right: 1.5rem; - } -} -.search-button-wrapper { - grid-column-end: -1 !important; - flex-direction: row !important; -} -.add-resource-modal { -} -.add-resource-wrapper { - .link { - color: theme(digitv2.lightTheme.primary); - } -} -.digit-toast-success { - margin-bottom: -0.5rem; -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss deleted file mode 100644 index 295d90c1264..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss +++ /dev/null @@ -1,173 +0,0 @@ -@import "../../typography.scss"; - -/* language selection issue*/ -.customBtn-selected { - background-color: theme(digitv2.lightTheme.primary); -} - -/* login screen issue*/ - -.primary-label-btn { - color: theme(digitv2.lightTheme.primary); -} - -/* landing screen issue*/ - -.employeeCard { - .complaint-links-container .header .logo { - background-color: theme(digitv2.lightTheme.primary); - } - - .complaint-links-container .body { - &.link { - color: theme(digitv2.lightTheme.primary); - } - .inbox-total { - background-color: theme(digitv2.lightTheme.primary); - } - } -} - -.employee .topbar .right .user-img-txt { - background-color: theme(digitv2.lightTheme.primary); -} -/* button component issue*/ - -.action-bar-wrap { - .submit-bar { - background-color: theme(digitv2.lightTheme.primary); - } -} - -.jk-digit-secondary-btn { - color: theme(digitv2.lightTheme.primary); - border-color: theme(digitv2.lightTheme.primary); - - svg { - fill: theme(digitv2.lightTheme.primary); - - path { - fill: theme(digitv2.lightTheme.primary); - } - } -} -.error-boundary .error-container button { - background-color: theme(digitv2.lightTheme.primary); -} - -/* inbox screen issue*/ - -.inbox-search-wrapper { - .search-tabs-container .search-tab-head-selected { - color: theme(digitv2.lightTheme.primary); - border-color: theme(digitv2.lightTheme.primary); - } - .submit-bar { - background-color: theme(digitv2.lightTheme.primary); - } - .search-component-table .link { - color: theme(digitv2.lightTheme.primary); - } - .link-label { - color: theme(digitv2.lightTheme.primary) !important; - } -} -.drag-drop-container .drag-drop-text .browse-text { - color: theme(digitv2.lightTheme.primary); -} -/* toast new componnet css added */ - -.toast-success { - gap: 0.5rem; - height: 3rem; - padding: 0.75rem 0.5rem 0.75rem 0.75rem !important; - background-color: theme(digitv2.alert.success); - transition: bottom 0.5s ease; - grid-gap: 0.5rem; - &.error { - background-color: theme(digitv2.alert.error) !important; - } - - &.warning { - background-color: #f19100; - - &.warning-buttons { - @apply block; - } - } - - h2 { - @apply text-left overflow-hidden whitespace-no-wrap flex-grow flex items-center h-6; - letter-spacing: 0rem; - color: theme(digitv2.lightTheme.paper); - margin: 0rem; - text-overflow: ellipsis; - font-family: Roboto; - font-weight: 500; - font-size: 1.25rem; - font-style: normal; - } - svg { - @apply flex-shrink-0; - } -} - -@keyframes slideInFromBottom { - from { - bottom: -3rem; - } - to { - bottom: 4rem; - } -} - -.toast-success.animate { - animation: slideInFromBottom 0.5s ease forwards; -} - -@media screen and (max-width: 768px) { - .topbar { - background: #0b4b66 !important; - color: #fff; - } -} -header { - @extend .typography.text-heading-xl; -} -.digit-button-primary{ - background-color: theme(digitv2.lightTheme.primary) !important; -} -.digit-button-secondary{ - .icon-label-container{ - h2{ - color: theme(digitv2.lightTheme.primary) !important; - } - } -} - -/*.digit-popup-wrap { - background: rgba(0, 0, 0, 0.7); - @apply flex fixed w-full h-full overflow-auto top-0 left-0 min-h-screen; - z-index: 10000; - max-width: 100% !important; - max-height: 100% !important; -} - -@screen dt { - .digit-popup-wrap { - background: rgba(0, 0, 0, 0.7); - @apply min-h-screen; - } -} - -.digit-popup-close-icon { - @apply flex justify-end; -}*/ - -.employee{ - .digit-employeeSidebar{ - .sidebar{ - z-index:999 - } - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss deleted file mode 100644 index 2b989e87305..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss +++ /dev/null @@ -1,481 +0,0 @@ -@import "./campaignCycle.scss"; -@import "./coreOverride.scss"; -@import "../../typography.scss"; - -.wbh-header-container { - margin-top: 1.5rem; -} -.main.digit-home-main { - margin-left: 92px; - .employee-app-wrapper.digit-home-app-wrapper { - margin-left: 0; - margin-right: 2rem; - .ground-container.digit-home-ground { - padding: 0; - .employee-app-container.digit-home-employee-app { - .ground-container.moduleCardWrapper.gridModuleWrapper.digit-home-moduleCardWrapper { - gap: 2.5rem; - margin-top: 2rem; - padding: 0; - display: grid !important; - grid-template-columns: repeat(auto-fill, minmax(263px, 1fr)); - .employeeCard.customEmployeeCard.card-home.home-action-cards { - margin: 0 !important; - min-width: 263px !important; - width: auto !important; - } - } - } - } - } -} -.campaign-cycle-container { - .popup-header-fix { - margin-top: 1.5rem !important; - } -} - -.tag.inbox-tag { - max-width: fit-content; - background-color: #d6d5d4; - border-radius: 2rem; - padding: 0.5rem; - display: flex; - align-items: center; - height: 2rem; - margin-bottom: 0.7rem; - grid-gap: 0.2rem; - gap: 0.2rem; -} -.mandatory-span { - margin-left: 0.5rem; - color: red !important; - font-size: 1rem; - font-weight: 700; -} - -.digit-employee-card-input.numeric { - margin-bottom: unset; -} - -.actionBarClass { - display: flex; - justify-content: space-between; - flex-direction: row-reverse; - z-index: 0; -} -.previous-button { - margin-left: 4rem; - min-width: 12.5rem; -} -.info-text { - padding-bottom: 1.5rem; -} - -.view-composer-header-section { - display: flex; - justify-content: space-between; - align-items: baseline; -} -.card-with-background { - margin-top: 1rem; - .card-head { - margin-bottom: 1rem; - color: #505a5f; - } -} -.no-data-found { - display: flex; - flex-direction: column; - align-items: center; - .error-msg { - margin-top: 1rem; - } -} -.search-tab-head { - color: #505a5f; -} -.search-tabs-container { - border-bottom: none; - margin-bottom: 0; -} -.delivery-preview-card { - margin-bottom: 1.5rem !important; - background-color: #fafafa; - border: 1px solid #d6d5d4; - width: 70%; - .custom-table-label { - font-size: 1.5rem; - font-weight: 700; - color: #505a5f; - margin-bottom: 1rem; - } - .campaign-attribute-table { - margin-bottom: 1rem; - border: 1px solid #d6d5d4; - overflow: hidden; - border-radius: 4px; - table { - border-width: 0px !important; - background-color: #fafafa; - border: 1px solid #d6d5d4; - border-collapse: collapse; - border-radius: 1rem; - tbody { - tr:nth-child(odd) { - background-color: white; - } - } - th { - border-right: 1px solid #d6d5d4; - } - th:last-child { - border-right: none; - } - td { - padding: 1rem; - border-right: 1px solid #d6d5d4; - } - td:last-child { - padding: 1rem; - border-right: none; - } - } - } - .campaign-product-table { - margin-bottom: 1rem; - border: 1px solid #d6d5d4; - overflow: hidden; - border-radius: 4px; - table { - background-color: #fafafa; - border: 1px solid #d6d5d4; - border-collapse: collapse; - border-radius: 1rem; - border-width: 0px !important; - tbody { - background-color: #fff; - tr:nth-child(odd) { - background-color: white; - } - } - th { - border-right: 1px solid #d6d5d4; - } - th:last-child { - border-right: none; - } - td { - padding: 1rem; - border-right: 1px solid #d6d5d4; - } - td:last-child { - border-right: none; - } - } - } -} -.cycle-paragraph { - font-weight: 700; - font-size: 24px; - color: #505a5f; - margin-top: 0.5rem; -} -.header-end { - margin-right: 1rem; -} -.digit-stepper-container { - margin-bottom: 1.5rem; -} -.employee-app-wrapper { - margin: 0rem 1rem; -} -input[type="date"]::-webkit-calendar-picker-indicator { - position: absolute; - right: 5px; - top: 20%; - transform: translateY(-10%); -} -.campaign-preview-edit-container { - display: flex; - gap: 1rem; - span { - color: theme(digitv2.lightTheme.primary); - } -} -.campaign-attribute-table { - border: 1px solid #d6d5d4; - overflow: hidden; - border-radius: 4px; - tbody { - tr:nth-child(odd) { - background-color: white; - } - } -} -tbody { - tr:nth-child(odd) { - background-color: white; - } -} -.popup-wrap.campaign-data-preview { - flex-direction: column; -} - -.digit-employee-card-input.numeric { - pointer-events: none; -} -.product-tag-container { - display: flex; - flex-wrap: wrap; - gap: 1.5rem; - margin-bottom: 1rem; -} - -.workbench-download-template-btn { - font-weight: 700; -} -.digit-employee-card-input.numeric { - text-align: center; -} -.in-between { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 2rem; - @media screen and (min-width: 1024px) { - grid-gap: 10rem; - } -} -.setup-campaign { - .setup-campaign-card { - padding-bottom: 1.5rem; - } - .digit-dropdown-options-card { - max-height: 10rem !important; - } - .digit-field { - margin-bottom: 0 !important; - } -} -.campaign-summary-container { - .setup-campaign-card { - .employeeCard.employeeCard-override { - padding: 1.5rem; - margin-bottom: 1.5rem !important; - } - } - .row { - justify-content: flex-start; - gap: 5rem; - h2 { - margin: 0; - width: 272px; - } - .value { - width: unset; - p { - margin: 0; - } - } - } - .digit-infobanner-wrap.error { - margin-left: 0; - margin-bottom: 1.5rem; - min-width: 100%; - .digit-button-primary { - height: 1.5rem; - background-color: #d4351c !important; - .icon-label-container.primary.large { - font-size: 14px; - .digit-button-label { - font-size: 14px; - color: #ffffff; - } - } - } - } -} -.view-composer-header-section { - .employee-card-sub-header { - @extend .typography.text-heading-m; - margin-bottom: 1.5rem; - } - .employee-card-sub-header.error { - color: #d4351c; - display: flex; - align-items: center; - gap: 0.5rem; - } -} -.add-new-product-container { - border: 1px solid #d6d5d4; - background-color: #fafafa; - width: 70%; - padding-top: 0; - .heading-bar { - font-weight: 700; - display: flex; - align-items: baseline; - justify-content: space-between; - .card-text { - margin-top: 1rem; - margin-bottom: 1rem; - } - } - .label-field-pair { - gap: 5rem; - align-items: baseline; - .product-label-field { - width: 12rem; - text-wrap: nowrap; - font-weight: 700; - } - } -} -.page-padding-fix { - margin-top: 1.5rem; -} -.addProductActionClass { - display: flex; - flex-direction: row-reverse; - justify-content: space-between; - .submit-bar { - width: max-content; - padding-left: 1.5rem; - padding-right: 1.5rem; - } -} -.loginFormStyleEmployee { - .loginCardClassName { - .digit-header-content { - &:not(label) { - display: flex; - justify-content: center; - } - } - } -} -.selecting-boundaries-dropdown { - .digit-multiselectdropdown-server { - max-height: 15rem; - } -} -.hover { - cursor: pointer; -} -.digit-dropdown-employee-select-wrap { - .digit-dropdown-employee-select-wrap--elipses { - font-size: 1rem !important; - } -} -.digit-dropdown-employee-select-wrap.language-dropdown { - .digit-dropdown-options-card { - min-width: fit-content; - } -} -.digit-popup-wrapper.boundaries-pop-module.default { - width: 36rem; - .digit-popup-footer { - .digit-popup-footer-buttons { - width: 100% !important; - display: grid; - grid-template-columns: 1fr 1fr; - .digit-button-secondary { - width: 100%; - } - .digit-button-primary { - width: 100%; - } - } - } -} -.campaign-type-alert-button { - .digit-button-label { - width: 100% !important; - } -} -.campaign-pop-module { - padding: 1.5rem; - border-radius: 4px; - width: 36rem; -} -.campaign-modal-heading { - font-size: 2rem; - font-weight: 700; - margin: 0 !important; -} -.campaign-pop-main { - font-size: 1.25rem; - padding: 0 !important; - font-size: 400; - .card-text { - margin-bottom: 1.5rem !important; - } - .popup-module-action-bar.campaign-pop-action { - .selector-button-border { - background-color: #ffffff; - border: 1px solid #c84c0e; - h2 { - color: #c84c0e !important; - } - } - } -} - -.digit-toast-success { - max-width: 90%; - margin-left: auto; - margin-right: auto; - height: auto; - .toast-label { - line-height: 1.5; - word-break: break-word; - height: auto; - white-space: unset; - } -} - -.digit-dropdown-select.error { - border: 1px solid #d4351c; -} -.campaign-type-wrapper { - .digit-error-icon-message-wrap { - margin-top: 4px; - font-size: 14px; - } -} -.individualElement { - h2 { - color: theme(digitv2.lightTheme.text-primary); - } -} -.link { - color: #c84c0e !important; -} -.employeeCard.employeeCard-override.card-error { - border: 1px solid #d4351c; -} -.label-field-pair.delivery-type-radio { - gap: 5rem; - .digit-radio-options-wrap { - gap: 2rem; - margin-bottom: 0 !important; - .radio-option-container { - margin-bottom: 0; - align-items: center; - } - } -} -.bold { - font-weight: 700; -} -.summary-doc-error { - p { - margin-top: 0; - margin-bottom: 0; - } - .digit-infobanner-wrap.error { - margin-bottom: 0.5rem; - margin-top: 1.5rem; - } -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss deleted file mode 100644 index 4a50014cf88..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss +++ /dev/null @@ -1,512 +0,0 @@ -.typography { - &.text-heading-xl { - font-family: theme(digitv2.fontFamily.rc); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.heading-xl.desktop); - } - - @media (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.heading-xl.tablet); - } - - @media (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.heading-xl.mobile); - } - } - - &.text-heading-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.heading-l.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.heading-l.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.heading-l.mobile); - } - } - - &.text-heading-m { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.heading-m.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.heading-m.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.heading-m.desktop); - } - } - - &.text-heading-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.heading-s.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.heading-s.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.heading-s.mobile); - } - } - - &.text-heading-xs { - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.heading-xs.mobile); - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - } - } - - &.text-caption-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.caption-l.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.caption-l.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.caption-l.mobile); - } - } - - &.text-caption-m { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.caption-m.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.caption-m.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.caption-m.mobile); - } - } - - &.text-caption-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.caption-s.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.caption-s.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.caption-s.desktop); - } - } - - &.text-body-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.regular); - color: theme(digitv2.lightTheme.text-primary); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.body-l.desktop); - line-height: theme(digitv2.lineHeight.line-height-body-l.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.body-l.tablet); - line-height: theme(digitv2.lineHeight.line-height-body-l.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.body-l.mobile); - line-height: theme(digitv2.lineHeight.line-height-body-l.mobile); - } - } - - &.text-body-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.regular); - color: theme(digitv2.lightTheme.text-primary); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.body-s.desktop); - line-height: theme(digitv2.lineHeight.line-height-body-s.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.body-s.tablet); - line-height: theme(digitv2.lineHeight.line-height-body-s.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.body-s.mobile); - line-height: theme(digitv2.lineHeight.line-height-body-s.mobile); - } - } - - &.text-body-xs { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.regular); - color: theme(digitv2.lightTheme.text-primary); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.body-xs.desktop); - line-height: theme(digitv2.lineHeight.line-height-body-xs.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.body-xs.tablet); - line-height: theme(digitv2.lineHeight.line-height-body-xs.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.body-xs.mobile); - line-height: theme(digitv2.lineHeight.line-height-body-xs.mobile); - } - } - - &.text-label { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.regular); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.label.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.label.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.label.mobile); - } - } - - &.text-link { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - text-decoration: theme(digitv2.textDecorationLine.underline); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.link.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.link.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.link.mobile); - } - } - - &.heading-xl { - font-family: theme(digitv2.fontFamily.rc); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.heading-xl.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.heading-xl.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.heading-xl.desktop); - } - } - - &.heading-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.heading-l.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.heading-l.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.heading-l.desktop); - } - } - - &.heading-m { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.heading-m.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.heading-m.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.heading-m.desktop); - } - } - - &.heading-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.heading-s.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.heading-s.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.heading-s.desktop); - } - } - - &.heading-xs { - font-size: theme(digitv2.fontSize.heading-xs.mobile); - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - } - - &.caption-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.caption-l.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.caption-l.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.caption-l.desktop); - } - } - - &.caption-m { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.caption-m.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.caption-m.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.caption-m.desktop); - } - } - - &.caption-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.caption-s.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.caption-s.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.caption-s.desktop); - } - } - - &.body-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.body-l.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.body-l.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.body-l.desktop); - } - } - - &.body-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.body-s.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.body-s.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.body-s.desktop); - } - } - - &.body-xs { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.body-xs.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.body-xs.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.body-xs.desktop); - } - } - - &.label { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.label.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.label.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.label.desktop); - } - } - - &.link { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - text-decoration: theme(digitv2.textDecorationLine.underline); - font-size: theme(digitv2.fontSize.link.desktop); - } - - &.button { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.medium); - font-size: theme(digitv2.fontSize.button.desktop); - } -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js deleted file mode 100644 index c9b2a06dedf..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js +++ /dev/null @@ -1,233 +0,0 @@ -module.exports = { - future: { - removeDeprecatedGapUtilities: true, - purgeLayersByDefault: true, - }, - purge: { enabled: true, content: ["./example/index.html"] }, - theme: { - screens: { - dt: "780px", - sm: { max: "425px" }, - }, - colors: { - primary: { - light: "#F18F5E", - main: "#F47738", - dark: "#C8602B", - }, - secondary: "#22394D", - text: { - primary: "#0B0C0C", - secondary: "#505A5F", - }, - link: { - normal: "#1D70B8", - hover: "#003078", - }, - border: "#D6D5D4", - inputBorder: "#464646", - "input-border": "#464646", - focus: "#F47738", - error: "#D4351C", - success: "#00703C", - black: "#000000", - grey: { - dark: "#9E9E9E", - mid: "#EEEEEE", - light: "#FAFAFA", - bg: "#E3E3E3", - }, - white: "#FFFFFF", - }, - fontFamily: { - sans: ["Roboto", "sans-serif"], - rc: ['"Roboto Condensed"', "sans-serif"], - }, - fontSize: { - "heading-xl-dt": ["48px", "56px"], - "heading-xl": ["32px", "40px"], - "heading-l-dt": ["36px", "40px"], - "heading-l": ["24px", "32px"], - "heading-m-dt": ["24px", "32px"], - "heading-m": ["18px", "28px"], - "heading-s": ["16px", "24px"], - "caption-xl-dt": ["27px", "32px"], - "caption-xl": ["18px", "26px"], - "caption-l-dt": ["24px", "28px"], - "caption-l": ["18px", "21px"], - "caption-m-dt": ["19px", "23px"], - "caption-m": ["16px", "19px"], - "form-field": ["16px", "20px"], - "body-l-dt": ["19px", "28px"], - "body-l": ["16px", "24px"], - "body-s-dt": ["16px", "24px"], - "body-s": ["14px", "16px"], - legend: ["19px", "23px"], - link: ["16px", "24px"], - "text-btn": ["16px", "24px"], - }, - fontWeight: { - regular: 400, - medium: 500, - bold: 700, - }, - padding: { - sm: "8px", - md: "16px", - lg: "24px", - xl: "36px", - }, - margin: { - xs: "4px", - sm: "8px", - md: "16px", - lg: "24px", - xl: "64px", - }, - borderWidth: { - default: "1px", - 0: "0", - 2: "1px", - 4: "4px", - 10: "10px", - }, - boxShadow: { - card: "0 1px 2px 0 rgba(0, 0, 0, 0.16)", - radiobtn: "0 0 0 5px #F47738", - }, - inset: { - 0: 0, - 6: "6px", - 10: "10px", - }, - extend: {}, - digitv2: { - lightTheme: { - primary: "#C84C0E", - "text-color-primary": "#0B0C0C", - "text-color-secondary": "#505A5F", - "text-color-disabled": "#B1B4B6", - background: "#EEEEEE", - paper: "#FFFFFF", - "paper-secondary": "#FAFAFA", - divider: "#D6D5D4", - "header-sidenav": "#0B4B66", - "input-border": "#505A5F", - "primary-bg": "#FEEFE7", - "text-primary": "#363636", - "error-v2": "#D4351C", - }, - alert: { - error: "#b91900", - "error-bg": "#EFC7C1", - success: "#00703C", - "success-bg": "#BAD6C9", - info: "#3498DB", - "info-bg": "#C7E0F1", - }, - chart: { - "chart-1": "#048BD0", - "chart-1-gradient": "#048BD0", - "chart-2": "#FBC02D", - "chart-2-gradient": "#FBC02D", - "chart-3": "#8E29BF", - "chart-4": "#EA8A3B", - "chart-5": "#0BABDE", - }, - fontSize: { - "heading-xl": { - mobile: "2rem", - tablet: "2.25rem", - desktop: "2.5rem", - }, - "heading-l": { - mobile: "1.5rem", - tablet: "1.75rem", - desktop: "2rem", - }, - "heading-m": { - mobile: "1.25rem", - tablet: "1.375rem", - desktop: "1.5rem", - }, - "heading-s": { - mobile: "1rem", - tablet: "1rem", - desktop: "1rem", - }, - "heading-xs": { - mobile: "0.75rem", - }, - "caption-l": { - mobile: "1.5rem", - tablet: "1.75rem", - desktop: "1.75rem", - }, - "caption-m": { - mobile: "1.25rem", - tablet: "1.5rem", - desktop: "1.5rem", - }, - "caption-s": { - mobile: "1rem", - tablet: "1.25rem", - desktop: "1.25rem", - }, - "body-l": { - mobile: "1rem", - tablet: "1.25rem", - desktop: "1.25rem", - }, - "body-s": { - mobile: "0.875rem", - tablet: "1rem", - desktop: "1rem", - }, - "body-xs": { - mobile: "0.75rem", - tablet: "0.875rem", - desktop: "0.875rem", - }, - label: { - mobile: "1rem", - tablet: "1rem", - desktop: "1rem", - }, - link: { - mobile: "1rem", - tablet: "1rem", - desktop: "1rem", - }, - }, - fontFamily: { - sans: ["Roboto"], - rc: ['"Roboto Condensed"'], - }, - fontStyle: { - normal: "normal", - italic: "italic", - }, - textDecorationLine: { - underline: "underline", - }, - fontWeight: { - regular: 400, - medium: 500, - bold: 700, - }, - lineHeight: { - "line-height-body-l": { mobile: "1.5rem", tablet: "1.75rem", desktop: "1.75rem" }, - "line-height-body-s": { mobile: "1.0938rem", tablet: "1.5rem", desktop: "1.5rem" }, - "line-height-body-xs": { mobile: "1.125rem", tablet: "1.5rem", desktop: "1.5rem" }, - normal: "normal", - }, - screens: { - mobile: "400px", - tablet: "768px", - desktop: "1024px", - }, - }, - }, - variants: {}, - plugins: [], -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md deleted file mode 100644 index 0d206b3021e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# digit-ui-module-workbench - -## Install - -```bash -npm install --save digit-ui-module-workbench -``` - -## Limitation - -```bash -This Package is more specific to DIGIT-UI's can be used across mission's -``` - -## Usage - -After adding the dependency make sure you have this dependency in - -```bash -frontend/micro-ui/web/package.json -``` - -```json -"@egovernments/digit-ui-module-workbench":"1.0.0", -``` - -then navigate to App.js - -```bash - frontend/micro-ui/web/src/App.js -``` - -```jsx -/** add this import **/ - -import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; - -/** inside enabledModules add this new module key **/ - -const enabledModules = ["workbench"]; - -/** inside init Function call this function **/ - -const initDigitUI = () => { - initWorkbenchComponents(); -}; - -``` - -In MDMS - -_Add this configuration to enable this module [MDMS Enabling Workbench Module](https://github.com/egovernments/works-mdms-data/blob/588d241ba3a9ab30f4d4c2c387a513da811620ca/data/pg/tenant/citymodule.json#L227)_ - -## List of Screens available in this versions were as follows - -1 . Search Master Data - > -Provides a screen based on Schema and renders the search result if data is present - > -It also provides a dynamic filter based on which data can be filtered - - -2 . Add Master Data based on selected schema - > -Provides a screen to add new master data according to the schema - > -Provides a Dropdown if it has any referenced master - -3 . Update Master data for selected data. - > -View the master data from search screen - > -Disable/Enable the master data if required - > -Update the master data value except the unique-identifier field mentioned in the schema - - - -4 . Localisation screens - > -Provides a screen to search the localisation present in the environment - > -Add new localisation - > -Update existing localisation - > -Bulk Upload of Localisation data - -5 . MDMS UI Schema - -6 . Data push for any API based on schema - -### Mandatory changes to use Workbench module - -1 . Assuming core module is already updated with 1.5.38+ and related changes were taken - -2 . add the following hook method in micro-ui-internals/packages/libraries/src/hooks/useCustomAPIMutationHook.js - -reference:: -https://github.com/egovernments/DIGIT-Dev/blob/6e711bdc005c226c7debd533209681fc77078a3e/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomAPIMutationHook.js - -3 . add the following utility method in micro-ui-internals/packages/libraries/src/utils/index.js -```jsx -didEmployeeHasAtleastOneRole - -const didEmployeeHasAtleastOneRole = (roles = []) => { - return roles.some((role) => didEmployeeHasRole(role)); -}; - -``` - -4 . stylesheet link has to be added -```jsx - -``` -Reference commit for the enabling workbench -https://github.com/egovernments/DIGIT-OSS/pull/99/commits/6e711bdc005c226c7debd533209681fc77078a3e - - - -### Changelog - -```bash -1.0.1-beta.1 Republished after merging with Master due to version issues. -1.0.0-beta.14 Added info message in localisation search -1.0.0-beta.13 Added new role to support hcm localisation create -1.0.0-beta.13 Added customisable label for custom dropdown through workbench ui schema -1.0.0-beta.11 Added customisable label for custom dropdown through workbench ui schema -1.0.0-beta.10 fixed the dropdown undefined issue -1.0.0-beta.9 Added new role to support hcm manage masters -1.0.0-beta.8 minor fixes -1.0.0-beta.7 Added Bulk Upload Ui for MDMS Add -1.0.0-beta.6 Added Bulk Upload Ui for MDMS Add -1.0.0-beta.5 Fixed some loading issue -1.0.0-beta.2 custom api support added -1.0.0-beta.1 republished due to some version issues -1.0.1 Fixes related to the limits -1.0.0 Workbench v1.0 release -1.0.0-beta workbench base version beta release -0.0.3 readme updated -0.0.2 readme updated -0.0.1 base version -``` - -### Contributors - -- [jagankumar-egov](https://github.com/jagankumar-egov) -- [nipun-egov](https://github.com/nipun-egov) - - -## License - -[MIT](https://choosealicense.com/licenses/mit/) - -## Documentation - -Documentation Site (https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) -Workbench Documentation(https://workbench.digit.org/platform/functional-specifications/workbench-ui) - -## Maintainer - -- [jagankumar-egov](https://www.github.com/jagankumar-egov) - - -### Published from DIGIT Frontend -DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/master) - - -![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) - diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json deleted file mode 100644 index 41e43fdb6fd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@egovernments/digit-ui-module-campaign-manager", - "version": "0.0.1", - "description": "Campaign", - "main": "dist/index.js", - "module": "dist/index.modern.js", - "source": "src/Module.js", - "files": [ - "dist" - ], - "scripts": { - "start": "microbundle-crl watch --no-compress --format modern,cjs", - "build": "microbundle-crl --compress --no-sourcemap --format cjs", - "prepublish": "yarn build" - }, - "peerDependencies": { - "react": "17.0.2", - "react-router-dom": "5.3.0" - }, - "dependencies": { - "@egovernments/digit-ui-react-components": "1.8.2-beta.6", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "@rjsf/core": "5.10.0", - "@rjsf/utils": "5.10.0", - "@rjsf/validator-ajv8": "5.10.0", - "ajv": "8.12.0", - "react": "17.0.2", - "react-date-range": "1.4.0", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "react-select": "5.7.4", - "react-table": "7.7.0", - "xlsx": "0.17.5", - "react-drag-drop-files": "^2.3.10", - "@cyntler/react-doc-viewer": "1.10.3" - }, - "author": "JaganKumar ", - "license": "MIT", - "keywords": [ - "digit", - "egov", - "dpg", - "digit-ui", - "workbench", - "campaign", - "Campaign" - ] -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js deleted file mode 100644 index cc2f33443d4..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js +++ /dev/null @@ -1,141 +0,0 @@ -import { Loader, TourProvider } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useRouteMatch } from "react-router-dom"; -import EmployeeApp from "./pages/employee"; -import { CustomisedHooks } from "./hooks"; -import { UICustomizations } from "./configs/UICustomizations"; -import CampaignCard from "./components/CampaignCard"; -import CycleConfiguration from "./pages/employee/CycleConfiguration"; -import DeliverySetup from "./pages/employee/deliveryRule"; -import TimelineCampaign from "./components/TimelineCampaign"; -import CampaignDates from "./components/CampaignDates"; -import CampaignType from "./components/CampaignType"; -import CampaignName from "./components/CampaignName"; -import MyCampaign from "./pages/employee/MyCampaign"; -import CampaignSummary from "./components/CampaignSummary"; -import CycleDetaisPreview from "./components/CycleDetaisPreview"; -import Response from "./pages/employee/Response"; -import SelectingBoundaries from "./components/SelectingBoundaries"; -import UploadData from "./components/UploadData"; -import CampaignSelection from "./components/CampaignType"; -import CampaignDocumentsPreview from "./components/CampaignDocumentsPreview"; -import AddProduct from "./pages/employee/AddProduct"; -import AddProductField from "./components/AddProductField"; -import CycleDataPreview from "./components/CycleDataPreview"; -import { ErrorBoundary } from "@egovernments/digit-ui-components"; -import CampaignResourceDocuments from "./components/CampaignResourceDocuments"; - -/** - * The CampaignModule function fetches store data based on state code, module code, and language, and - * renders the EmployeeApp component within a TourProvider component if the data is not loading. - * @returns The CampaignModule component returns either a Loader component if data is still loading, or - * a TourProvider component wrapping an EmployeeApp component with specific props passed to it. - */ -const CampaignModule = ({ stateCode, userType, tenants }) => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - const { data: BOUNDARY_HIERARCHY_TYPE } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }], { - select: (data) => { - return data?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy; - }, - }); - - const moduleCode = ["campaignmanager", "workbench", "mdms", "schema", "hcm-admin-schemas", `boundary-${BOUNDARY_HIERARCHY_TYPE}`]; - const { path, url } = useRouteMatch(); - const language = Digit.StoreData.getCurrentLanguage(); - const { isLoading, data: store } = Digit.Services.useStore({ - stateCode, - moduleCode, - language, - }); - - if (isLoading) { - return ; - } - - return ( - - - - - - ); -}; - -const componentsToRegister = { - CampaignModule: CampaignModule, - CampaignCard: CampaignCard, - UploadData, - DeliveryRule: DeliverySetup, - CycleConfiguration: CycleConfiguration, - TimelineCampaign, - CampaignDates, - CampaignType, - CampaignName, - MyCampaign, - CampaignSummary, - CycleDetaisPreview, - Response, - SelectingBoundaries, - CampaignSelection, - CampaignDocumentsPreview: CampaignDocumentsPreview, - AddProduct, - AddProductField, - CycleDataPreview, - CampaignResourceDocuments, -}; - -const overrideHooks = () => { - Object.keys(CustomisedHooks).map((ele) => { - if (ele === "Hooks") { - Object.keys(CustomisedHooks[ele]).map((hook) => { - Object.keys(CustomisedHooks[ele][hook]).map((method) => { - setupHooks(hook, method, CustomisedHooks[ele][hook][method]); - }); - }); - } else if (ele === "Utils") { - Object.keys(CustomisedHooks[ele]).map((hook) => { - Object.keys(CustomisedHooks[ele][hook]).map((method) => { - setupHooks(hook, method, CustomisedHooks[ele][hook][method], false); - }); - }); - } else { - Object.keys(CustomisedHooks[ele]).map((method) => { - setupLibraries(ele, method, CustomisedHooks[ele][method]); - }); - } - }); -}; - -/* To Overide any existing hook we need to use similar method */ -const setupHooks = (HookName, HookFunction, method, isHook = true) => { - window.Digit = window.Digit || {}; - window.Digit[isHook ? "Hooks" : "Utils"] = window.Digit[isHook ? "Hooks" : "Utils"] || {}; - window.Digit[isHook ? "Hooks" : "Utils"][HookName] = window.Digit[isHook ? "Hooks" : "Utils"][HookName] || {}; - window.Digit[isHook ? "Hooks" : "Utils"][HookName][HookFunction] = method; -}; -/* To Overide any existing libraries we need to use similar method */ -const setupLibraries = (Library, service, method) => { - window.Digit = window.Digit || {}; - window.Digit[Library] = window.Digit[Library] || {}; - window.Digit[Library][service] = method; -}; - -/* To Overide any existing config/middlewares we need to use similar method */ -const updateCustomConfigs = () => { - setupLibraries("Customizations", "commonUiConfig", { ...window?.Digit?.Customizations?.commonUiConfig, ...UICustomizations }); - // setupLibraries("Utils", "parsingUtils", { ...window?.Digit?.Utils?.parsingUtils, ...parsingUtils }); -}; - -/** - * The `initCampaignComponents` function initializes campaign components by overriding hooks, updating - * custom configurations, and registering components. - */ -const initCampaignComponents = () => { - overrideHooks(); - updateCustomConfigs(); - Object.entries(componentsToRegister).forEach(([key, value]) => { - Digit.ComponentRegistryService.setComponent(key, value); - }); -}; - -export { initCampaignComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js deleted file mode 100644 index 94a73fd6b24..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js +++ /dev/null @@ -1,144 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { AddIcon, Button, Card, CardText, Header, TextInput, Dropdown } from "@egovernments/digit-ui-react-components"; -import { useTranslation } from "react-i18next"; -import { LabelFieldPair } from "@egovernments/digit-ui-react-components"; -import { DustbinIcon } from "./icons/DustbinIcon"; -// import { productType } from "../configs/productType"; -import { PRIMARY_COLOR } from "../utils"; - -const AddProductField = ({ onSelect }) => { - const { t } = useTranslation(); - const tenantId = Digit.ULBService.getCurrentTenantId(); - const { isLoading: productTypeLoading, data: productType } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "productType" }], { - select: (data) => { - return data?.["HCM-ADMIN-CONSOLE"]?.productType; - }, - }); - const [productFieldData, setProductFieldData] = useState([{ key: 1, name: null, type: null, variant: null }]); - - useEffect(() => { - onSelect("addProduct", productFieldData); - }, [productFieldData]); - - const addMoreField = () => { - setProductFieldData((prev) => [ - ...prev, - { - key: prev.length + 1, - name: null, - type: null, - variant: null, - }, - ]); - }; - - const deleteProductField = (index) => { - setProductFieldData((prev) => { - const temp = prev.filter((i) => i.key !== index); - return temp.map((i, n) => ({ ...i, key: n + 1 })); - }); - }; - - const handleUpdateField = (data, target, index) => { - setProductFieldData((prev) => { - return prev.map((i) => { - if (i.key === index) { - return { - ...i, - [target]: data, - }; - } - return { - ...i, - }; - }); - }); - }; - - return ( - -
{t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_HEADER`)}
-

- {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_PRE_TEXT`)} {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_BOLD_TEXT`)} - {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_POST_TEXT`)} -

- {productFieldData?.map((field, index) => { - return ( - -
- Product {field?.key} - {productFieldData?.length > 1 && ( -
deleteProductField(field.key)} - style={{ - cursor: "pointer", - fontWeight: "600", - marginLeft: "1rem", - fontSize: "1rem", - color: PRIMARY_COLOR, - display: "flex", - gap: "0.5rem", - alignItems: "center", - marginTop: "1rem", - }} - > - - {t(`CAMPAIGN_DELETE_ROW_TEXT`)} -
- )} -
- -
- {`${t("HCM_PRODUCT_NAME")}`} - * -
- handleUpdateField(event.target.value, "name", field.key)} - /> -
- -
- {`${t("HCM_PRODUCT_TYPE")}`} - * -
- { - handleUpdateField(value, "type", field.key); - }} - /> -
- -
- {`${t("HCM_PRODUCT_VARIANT")}`} - * -
- handleUpdateField(event.target.value, "variant", field?.key)} - /> -
-
- ); - })} - - ))} - - ); -}; - -const CycleDataPreview = ({ data, items, index, errors, onErrorClick, cardErrors }) => { - const { t } = useTranslation(); - const [deliveryData, setDeliveryData] = useState(data?.deliveries); - const [activeTab, setActiveTab] = useState(1); - - useEffect(() => { - setDeliveryData(data?.deliveries); - }, [data?.deliveries]); - - const handleTabChange = (tabIndex, index) => { - setDeliveryData((prev) => { - return prev.map((i) => { - if (i.deliveryIndex == tabIndex) { - return { - ...i, - active: true, - }; - } else { - return { - ...i, - active: false, - }; - } - }); - }); - }; - // return null; - return ( - <> - {cardErrors?.map((i) => ( - ]} - /> - ))} - {/* {i.error ? i.error : i.message)} */} -
- {data?.startDate && ( - - )} - {data?.endDate && ( - - )} -
- -
- - - - {deliveryData - .find((i) => i.active === true) - ?.deliveryRules?.map((rules, ruleIndex) => { - return ( - - {rules?.attributes?.length > 0 && ( - - )} - {rules?.products?.length > 0 && ( - - )} - - ); - })} - - {/* - {item?.conditions?.length > 0 && ( - - )} - {item?.products?.length > 0 && ( - - )} - */} - - ); -}; - -export default CycleDataPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js deleted file mode 100644 index 515b25191d9..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js +++ /dev/null @@ -1,143 +0,0 @@ -import { Card, LabelFieldPair, Row } from "@egovernments/digit-ui-react-components"; -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import DetailsTable from "./DetailsTable"; - -function mergeObjects(item) { - const arr = item?.conditions; - const mergedArr = []; - const mergedAttributes = new Set(); - - arr.forEach((obj) => { - if (!mergedAttributes.has(obj.attribute)) { - const sameAttrObjs = arr.filter((o) => o.attribute === obj.attribute); - - if (sameAttrObjs.length > 1) { - const fromValue = Math.min(...sameAttrObjs.map((o) => o.value)); - const toValue = Math.max(...sameAttrObjs.map((o) => o.value)); - - mergedArr.push({ - fromValue, - toValue, - value: fromValue > 0 && toValue > 0 ? `${fromValue} to ${toValue}` : null, - operator: "IN_BETWEEN", - attribute: obj.attribute, - }); - - mergedAttributes.add(obj.attribute); - } else { - mergedArr.push(obj); - } - } - }); - - return { ...item, conditions: mergedArr }; -} - -const CycleDetaisPreview = ({ data, items, index }) => { - const { t } = useTranslation(); - const item = mergeObjects(items); - - return ( - <> - - - {/* - {`${t("CYCLE_NUMBER")}`} - {item?.cycleNumber} - - - {`${t("DELIVERY_NUMBER")}`} - {item?.deliveryNumber} - */} - {item?.startDate || item?.endDate ? ( - -
-

- {t(`CYCLE`)} {item?.cycleNumber} -

-
- {item?.startDate && ( - - )} - {item?.endDate && ( - - )} -
- ) : null} - - - {item?.conditions?.length > 0 && ( - - )} - {item?.products?.length > 0 && ( - - )} - - - ); -}; - -export default CycleDetaisPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js deleted file mode 100644 index 5c6e01fcc22..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js +++ /dev/null @@ -1,76 +0,0 @@ -import React, { Fragment } from "react"; -import { useTable } from "react-table"; -import { useTranslation } from "react-i18next"; -import { CardLabel, CardSubHeader } from "@egovernments/digit-ui-react-components"; - -const DetailsTable = ({ className = "", columnsData, rowsData, summaryRows, cardHeader }) => { - const { t } = useTranslation(); - - const columns = React.useMemo(() => columnsData, [t]); - - const data = React.useMemo(() => { - const temp = rowsData.map((i) => ({ - ...i, - operator: t(i?.operator), - attribute: i?.attribute ? t(`CAMPAIGN_ATTRIBUTE_${i?.attribute?.toUpperCase()}`) : "", - })); - return temp; - }, [rowsData]); - - const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ - columns, - data, - }); - - return ( - <> - {cardHeader && ( - - {cardHeader?.value} - - )} -
- - - {headerGroups.map((headerGroup) => ( - - {headerGroup.headers.map((column) => ( - - ))} - - ))} - - - - {rows.map((row) => { - prepareRow(row); - return ( - - {row.cells.map((cell) => ( - - ))} - - ); - })} - - {summaryRows && ( - - {summaryRows.map((cell, index) => ( - - ))} - - )} - -
- {column.render("Header")} -
- {cell.render("Cell")} -
- {index === 4 ? {cell} : cell} -
-
- - ); -}; - -export default DetailsTable; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js deleted file mode 100644 index 9b61bf67136..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from "react"; -export const DocumentIcon = ({ styles = {}, className, fill = "#D4351C" }) => ( - - - - - - - - - - - - - - - - - - - - -); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js deleted file mode 100644 index 89d7b574032..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js +++ /dev/null @@ -1,47 +0,0 @@ -import React, { useState } from "react"; - -const PlusMinusInput = (props, customProps) => { - let count = props?.defaultValues || 1; - - function incrementCount() { - if (count >= 1) { - count = count + 1; - props.onSelect(count); - } else { - count = 1; - props.onSelect(count); - } - } - function decrementCount() { - if (count > 1) { - count = count - 1; - props.onSelect(count); - } else { - count = 1; - props.onSelect(count); - } - } - - return ( - -
- - - -
-
- ); -}; - -export default PlusMinusInput; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js deleted file mode 100644 index b04159181a6..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; -import { Close } from "@egovernments/digit-ui-react-components"; - -const RemoveableTagNew = ({ text = {}, onClick, extraStyles, disabled = false }) => ( -
- {text?.label && {`${text?.label} :`}} - - {text?.value} - - - - -
-); - -export default RemoveableTagNew; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js deleted file mode 100644 index 239cf948ee0..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js +++ /dev/null @@ -1,542 +0,0 @@ -import React, { useEffect, useState, Fragment, useMemo } from "react"; -import { CardText, LabelFieldPair, Card, Header, CardLabel, LoaderWithGap } from "@egovernments/digit-ui-react-components"; -import { useTranslation } from "react-i18next"; -import { InfoCard, MultiSelectDropdown, PopUp, Button, Toast } from "@egovernments/digit-ui-components"; -import { mailConfig } from "../configs/mailConfig"; -/** - * The function `SelectingBoundaries` in JavaScript handles the selection of boundaries based on - * hierarchy data and allows users to choose specific boundaries within the hierarchy. - * @returns The `SelectingBoundaries` component is being returned. It consists of JSX elements - * including Cards, Headers, Dropdowns, MultiSelectDropdowns, and InfoCard. The component allows users - * to select hierarchy types and boundaries based on the data fetched from API calls. It also handles - * the selection of boundaries and updates the state accordingly. The component is designed to be - * interactive and user-friendly for selecting boundaries within - */ -function SelectingBoundaries({ onSelect, formData, ...props }) { - const { t } = useTranslation(); - const tenantId = Digit.ULBService.getCurrentTenantId(); - const [params, setParams] = useState(props?.props?.dataParams); - const [hierarchy, setHierarchy] = useState(params?.hierarchyType); - const [boundaryType, setBoundaryType] = useState( - props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData ? undefined : null - ); - const [targetedData, setTargetedData] = useState(); - const [boundaryData, setBoundaryData] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || {}); - // const [parentArray, setParentArray] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData.filter(item => item.includeAllChildren).map(item => item.code) || null); - const [parentArray, setParentArray] = useState(null); - const [boundaryTypeDataresult, setBoundaryTypeDataresult] = useState(null); - const [selectedData, setSelectedData] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData || []); - const [parentBoundaryTypeRoot, setParentBoundaryTypeRoot] = useState( - (props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData?.find((item) => item?.isRoot === true) || {}) - ?.boundaryType || null - ); - const [showToast, setShowToast] = useState(null); - const [updatedHierarchy, setUpdatedHierarchy] = useState({}); - const [hierarchyTypeDataresult, setHierarchyTypeDataresult] = useState(params?.hierarchy); - const [executionCount, setExecutionCount] = useState(0); - // State variable to store the lowest hierarchy level - // const [lowestHierarchy, setLowestHierarchy] = useState(null); - const [showPopUp, setShowPopUp] = useState(null); - const [restrictSelection, setRestrictSelection] = useState(null); - const [updateBoundary, setUpdateBoundary] = useState(null); - const [loaderEnabled, setLoaderEnabled] = useState(false); - const { isLoading, data: hierarchyConfig } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }]); - - // const lowestHierarchy = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy; - const lowestHierarchy = useMemo(() => hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy, [hierarchyConfig]); - const lowestChild = hierarchyTypeDataresult?.boundaryHierarchy.filter((item) => item.parentBoundaryType === lowestHierarchy)?.[0]?.boundaryType; - const searchParams = new URLSearchParams(location.search); - const isDraft = searchParams.get("draft"); - - useEffect(() => { - if (!updateBoundary) { - if ( - props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.length > 0 || - props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.length > 0 || - props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.length > 0 - ) { - setRestrictSelection(true); - } - } - }, [props?.props?.sessionData, updateBoundary]); - - useEffect(() => { - if (props?.props?.dataParams) { - setParams(props?.props?.dataParams); - } - }, [props?.props?.dataParams]); - - useEffect(() => { - onSelect("boundaryType", { boundaryData: boundaryData, selectedData: selectedData, updateBoundary: updateBoundary }); - }, [boundaryData, selectedData]); - - useEffect(() => { - setHierarchy(params?.hierarchyType); - }, [params?.hierarchyType]); - - useEffect(() => { - if (params?.hierarchy) { - const sortHierarchy = (hierarchy) => { - const boundaryMap = new Map(); - hierarchy.forEach(item => { - boundaryMap.set(item.boundaryType, item); - }); - - const sortedHierarchy = []; - let currentType = null; - - while (sortedHierarchy.length < hierarchy.length) { - for (let i = 0; i < hierarchy.length; i++) { - if (hierarchy[i].parentBoundaryType === currentType) { - sortedHierarchy.push(hierarchy[i]); - currentType = hierarchy[i].boundaryType; - break; - } - } - } - - return sortedHierarchy; - }; - - const sortedHierarchy = sortHierarchy(params.hierarchy.boundaryHierarchy); - setHierarchyTypeDataresult({ - ...params.hierarchy, - boundaryHierarchy: sortedHierarchy - }); - } - }, [params?.hierarchy]); - - useEffect(() => { - if (executionCount < 5) { - onSelect("boundaryType", { boundaryData: boundaryData, selectedData: selectedData, updateBoundary: updateBoundary }); - setExecutionCount((prevCount) => prevCount + 1); - } - }); - - useEffect(() => { - setBoundaryData( - props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData - ? props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData - : {} - ); - setSelectedData( - props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData - ? props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData - : [] - ); - }, [props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType]); - - const closeToast = () => { - setShowToast(null); - }; - - useEffect(() => { - if (hierarchyTypeDataresult) { - const boundaryDataObj = {}; - hierarchyTypeDataresult?.boundaryHierarchy?.forEach((boundary) => { - boundaryDataObj[boundary?.boundaryType] = []; - }); - if (!props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || Object.keys(boundaryData).length === 0) { - setBoundaryData(boundaryDataObj); - } - const boundaryWithTypeNullParent = hierarchyTypeDataresult?.boundaryHierarchy?.find((boundary) => boundary?.parentBoundaryType === null); - // Set the boundary type with null parentBoundaryType - if (boundaryWithTypeNullParent) { - if (!props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || Object.keys(boundaryData).length === 0) { - setBoundaryType(boundaryWithTypeNullParent?.boundaryType); - } - setParentBoundaryTypeRoot(boundaryWithTypeNullParent?.boundaryType); - } - createHierarchyStructure(hierarchyTypeDataresult); - } - }, [hierarchyTypeDataresult]); - - function createHierarchyStructure(hierarchyTypeDataresult) { - const hierarchyStructure = {}; - - // Recursive function to gather all descendants for a given boundary type - function gatherDescendants(boundaryType) { - const descendants = []; - hierarchyTypeDataresult; - - // Find all children for the current boundary type - const children = hierarchyTypeDataresult?.boundaryHierarchy?.filter((item) => item?.parentBoundaryType === boundaryType); - - // Recursively gather descendants for each child - children.forEach((child) => { - const childBoundaryType = child?.boundaryType; - const childDescendants = gatherDescendants(childBoundaryType); - descendants.push(childBoundaryType, ...childDescendants); - }); - - return descendants; - } - - // Iterate through the boundaryHierarchy array to populate hierarchyStructure - hierarchyTypeDataresult?.boundaryHierarchy?.forEach((item) => { - const boundaryType = item?.boundaryType; - const descendants = gatherDescendants(boundaryType); - - hierarchyStructure[boundaryType] = descendants; - }); - - setUpdatedHierarchy(hierarchyStructure); - } - - const newData = []; - const fetchBoundaryTypeData = async () => { - if (boundaryType === undefined || boundaryType === lowestChild) { - // Do nothing if boundaryType is undefined - return; - } - if (parentArray === null) { - const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ - url: "/boundary-service/boundary-relationships/_search", - params: { - tenantId: tenantId, - hierarchyType: hierarchy, - boundaryType: boundaryType, - parent: null, - }, - body: {}, - }); - // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); - const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; - setBoundaryTypeDataresult([{ parentCode: null, boundaryTypeData: boundaryTypeData }]); - // closeToast(); - } else { - // for (const parentCode of parentArray) { - // const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ - // url: "/boundary-service/boundary-relationships/_search", - // params: { - // tenantId: tenantId, - // hierarchyType: hierarchy, - // boundaryType: boundaryType, - // parent: parentCode, - // }, - // body: {}, - // }); - // // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); - // setLoaderEnabled(true); - // const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; - // newData.push({ parentCode, boundaryTypeData }); - // } - setLoaderEnabled(true); - const temp = await Digit.Hooks.campaign.useParallelSearch({ - parentArray: parentArray, - tenantId: tenantId, - boundaryType: boundaryType, - hierarchy: hierarchy, - targetedData: targetedData, - }); - const newDataArray = [...newData, ...temp]; - setBoundaryTypeDataresult(newDataArray); - setTimeout(() => { - setLoaderEnabled(false); - }, 100); - // closeToast(); - } - }; - - useEffect(() => { - fetchBoundaryTypeData(); - }, [boundaryType, parentArray, selectedData]); - - useEffect(() => { - if (boundaryTypeDataresult) { - if (boundaryType !== undefined) { - const updatedBoundaryData = { - ...boundaryData, - [boundaryType]: boundaryTypeDataresult, - }; - setBoundaryData(updatedBoundaryData); - } else { - const updatedBoundaryData = { - ...boundaryData, - [boundaryTypeDataresult?.[0]?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.[0]?.boundaryType]: boundaryTypeDataresult, - }; - setBoundaryData(updatedBoundaryData); - } - } - }, [boundaryTypeDataresult]); - - const checkDataPresent = ({ action }) => { - if (action === false) { - setShowPopUp(false); - setUpdateBoundary(true); - setRestrictSelection(false); - return; - } - if (action === true) { - setShowPopUp(false); - setUpdateBoundary(false); - return; - } - }; - - const handleBoundaryChange = (data, boundary) => { - setTargetedData(boundary?.boundaryType); - if ( - !updateBoundary && - restrictSelection && - (props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.length > 0 || - props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.length > 0 || - props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.length > 0) - ) { - setShowPopUp(true); - return; - } - if (!data || data.length === 0) { - const check = updatedHierarchy[boundary?.boundaryType]; - - if (check) { - const typesToRemove = [boundary?.boundaryType, ...check]; - const updatedSelectedData = selectedData?.filter((item) => !typesToRemove?.includes(item?.type)); - const updatedBoundaryData = { ...boundaryData }; - - typesToRemove.forEach((type) => { - if (type !== boundary?.boundaryType && updatedBoundaryData?.hasOwnProperty(type)) { - updatedBoundaryData[type] = []; - } - }); - if (!_.isEqual(selectedData, updatedSelectedData)) { - setSelectedData(updatedSelectedData); - } - setBoundaryData(updatedBoundaryData); - } - return; - } - - let res = []; - data && - data?.map((ob) => { - res.push(ob?.[1]); - }); - - // const transformedRes = res?.map((item) => ({ - // code: item.code, - // type: item.type || item.boundaryType, - // isRoot: item.boundaryType === parentBoundaryTypeRoot, - // includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, - // parent: item?.parent, - // })); - - let transformedRes = []; - if (!isDraft) { - transformedRes = res?.map((item) => ({ - code: item.code, - type: item.type || item.boundaryType, - isRoot: item.boundaryType === parentBoundaryTypeRoot, - includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, - parent: item?.parent, - })); - } else { - // transformedRes = selectedData.filter((item) => item?.type === boundary?.boundaryType) - const filteredData = selectedData.filter((item) => item?.type === boundary?.boundaryType); - if (filteredData.length === 0) { - // If no selected data for the particular boundary type, run the transformation logic - transformedRes = res?.map((item) => ({ - code: item.code, - type: item.type || item.boundaryType, - isRoot: item.boundaryType === parentBoundaryTypeRoot, - includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, - parent: item?.parent, - })); - } else { - transformedRes = filteredData; - } - } - - const newBoundaryType = transformedRes?.[0]?.type; - const existingBoundaryType = selectedData?.length > 0 ? selectedData?.[0]?.type : null; - if (existingBoundaryType === newBoundaryType) { - // Update only the data for the specific boundaryType - const flattenedRes = transformedRes.flat(); - const updatedSelectedData = selectedData - ?.map((item) => { - if (item.type === newBoundaryType) { - return transformedRes?.flat(); - } else { - return item; - } - }) - .flat(); - if (!_.isEqual(selectedData, updatedSelectedData)) { - setSelectedData(updatedSelectedData); - } - } else { - // Update only the data for the new boundaryType - const mergedData = [...selectedData?.filter((item) => item?.type !== newBoundaryType), ...transformedRes]; - - // Filter out items with undefined type - const filteredData = mergedData?.filter( - (item, index, self) => item?.type !== undefined && index === self?.findIndex((t) => t?.code === item?.code) - ); - - // Filter out items whose parent is not present in the array - - const updatedSelectedData = []; - const addChildren = (item) => { - updatedSelectedData.push(item); - const children = filteredData.filter((child) => child.parent === item.code); - children.forEach((child) => addChildren(child)); - }; - filteredData.filter((item) => item.isRoot).forEach((rootItem) => addChildren(rootItem)); - if (!_.isEqual(selectedData, updatedSelectedData)) { - setSelectedData(updatedSelectedData); - } - } - const parentBoundaryEntry = hierarchyTypeDataresult - ? hierarchyTypeDataresult?.boundaryHierarchy?.find( - (e) => e?.parentBoundaryType === res?.[0]?.boundaryType || e?.parentBoundaryType === res?.[0]?.type - ) - : null; - setBoundaryType(parentBoundaryEntry?.boundaryType); - const codes = res?.map((item) => item?.code); - if (JSON.stringify(codes) !== JSON.stringify(parentArray)) { - setParentArray(codes); - } - }; - - return ( - <> - {loaderEnabled && } - -
-
{t(`CAMPAIGN_SELECT_BOUNDARY`)}
- {t(`CAMPAIGN_SELECT_BOUNDARIES_DESCRIPTION`)} - {hierarchyTypeDataresult?.boundaryHierarchy - .filter((boundary, index, array) => { - // Find the index of the lowest hierarchy - const lowestIndex = array.findIndex((b) => b.boundaryType === lowestHierarchy); - // Include only those boundaries that are above or equal to the lowest hierarchy - return index <= lowestIndex; - }) - .map((boundary, index) => - boundary?.parentBoundaryType == null ? ( - - - {/* {t(`${hierarchy}_${boundary?.boundaryType}`?.toUpperCase())} */} - {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} - - * - -
- item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary)?.flat() || [] - } - optionsKey={"code"} - selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} - onSelect={(value) => { - handleBoundaryChange(value, boundary); - }} - /> -
-
- ) : ( - - - {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} - * - -
- ({ - code: item?.parentCode, - options: - item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.map((child) => ({ - code: child?.code, - type: child?.boundaryType, - parent: item?.parentCode, - })) || [], - })) || [] - } - optionsKey={"code"} - onSelect={(value) => { - handleBoundaryChange(value, boundary); - }} - selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} - addCategorySelectAllCheck={true} - addSelectAllCheck={true} - variant="nestedmultiselect" - /> -
-
- ) - )} -
-
- - {t("HCM_BOUNDARY_INFO ")} - - {mailConfig?.mailId} - - , - ]} - label={"Info"} - /> - {showPopUp && ( - - {t("ES_CAMPAIGN_UPDATE_BOUNDARY_MODAL_TEXT") + " "} - , - ]} - onOverlayClick={() => { - setShowPopUp(false); - }} - footerChildren={[ - - ))} - - ); -}; - -const TabContent = ({ activeSubTab, subTabCount = 3, onSubTabChange, project }) => { - const { campaignData, dispatchCampaignData } = useContext(CycleContext); - const { t } = useTranslation(); - - return ( - - -
- {t(`CAMPAIGN_TAB_TEXT`)} - {t(`CAMPAIGN_TAB_SUB_TEXT_${project?.code ? project?.code?.toUpperCase() : project?.toUpperCase()}`)} -
- {/* Add content specific to each tab as needed */} - , - - {t(`CAMPAIGN_TAB_INFO_TEXT_${project?.code ? project?.code?.toUpperCase() : project?.toUpperCase()}`)} - - ]} - label={"Info"} - /> -
- ); -}; - -const SubTabs = ({ onSubTabChange }) => { - const { campaignData, dispatchCampaignData } = useContext(CycleContext); - const { t } = useTranslation(); - - return ( -
- {campaignData - ?.find((i) => i?.active === true) - ?.deliveries.map((_, index) => ( - - ))} -
- ); -}; - -const MultiTab = ({ tabCount = 3, subTabCount = 2 }) => { - const [activeTab, setActiveTab] = useState(0); - const [activeSubTab, setActiveSubTab] = useState(0); - const { campaignData, dispatchCampaignData } = useContext(CycleContext); - const { t } = useTranslation(); - const tempSession = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA"); - const handleTabChange = (tabIndex, index) => { - dispatchCampaignData({ - type: "TAB_CHANGE_UPDATE", - payload: { tabIndex: tabIndex, index: index }, // Your updated campaign data - }); - setActiveTab(index); - setActiveSubTab(0); // Reset sub-tab when changing the main tab - }; - - const handleSubTabChange = (subTabIndex, itemIndex) => { - dispatchCampaignData({ - type: "SUBTAB_CHANGE_UPDATE", - payload: { subTabIndex: subTabIndex }, // Your updated campaign data - }); - }; - - return ( - <> -
- {t( - `CAMPAIGN_PROJECT_${ - tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code - ? tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code?.toUpperCase() - : tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.toUpperCase() - }` - )} -
- -
-
- -
- - -
- - ); -}; - -export default MultiTab; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js deleted file mode 100644 index ebdf2c5088f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js +++ /dev/null @@ -1,531 +0,0 @@ -import React, { createContext, useContext, useEffect, useReducer, useState } from "react"; -import MultiTab from "./MultiTabcontext"; -import { Loader } from "@egovernments/digit-ui-react-components"; -// import { deliveryConfig } from "../../../configs/deliveryConfig"; - -const CycleContext = createContext(); - -function makeSequential(jsonArray, keyName) { - return jsonArray.map((item, index) => ({ - ...item, - [keyName]: index + 1, - })); -} - -function DeliverySetup({ onSelect, config, formData, control, tabCount = 2, subTabCount = 3, ...props }) { - // Campaign Tab Skeleton function - const [cycleData, setCycleData] = useState(config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure); - const saved = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule; - const selectedProjectType = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_TYPE?.projectType?.code; - const tenantId = Digit.ULBService.getCurrentTenantId(); - const searchParams = new URLSearchParams(location.search); - const activeCycle = searchParams.get("activeCycle"); - const { isLoading: deliveryConfigLoading, data: filteredDeliveryConfig } = Digit.Hooks.useCustomMDMS( - tenantId, - "HCM-ADMIN-CONSOLE", - [{ name: "deliveryConfig" }], - { - select: (data) => { - const temp = data?.["HCM-ADMIN-CONSOLE"]?.deliveryConfig; - return temp?.find((i) => i?.projectType === selectedProjectType); - // return deliveryConfig?.find((i) => i?.projectType === selectedProjectType); - }, - } - ); - // const [filteredDeliveryConfig, setFilteredDeliveryConfig] = useState(deliveryConfig?.find((i) => i?.projectType === selectedProjectType)); - // useEffect(() => { - // if (!deliveryConfigLoading) { - // const temp = deliveryConfig?.find((i) => i?.projectType === selectedProjectType); - // setFilteredDeliveryConfig(temp); - // } - // }, [deliveryConfigLoading, filteredDeliveryConfig]); - // const filteredDeliveryConfig = deliveryConfig.find((i) => i.projectType === selectedProjectType); - useEffect(() => { - setCycleData(config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure); - }, [config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure]); - - const generateTabsData = (tabs, subTabs) => { - if (!saved || saved?.length === 0) { - return [...Array(tabs)].map((_, tabIndex) => ({ - cycleIndex: `${tabIndex + 1}`, - active: activeCycle == tabIndex + 1 ? true : tabIndex === 0 ? true : false, - deliveries: [...Array(subTabs || 1)].map((_, subTabIndex) => ({ - deliveryIndex: `${subTabIndex + 1}`, - active: subTabIndex === 0 ? true : false, - deliveryRules: - filteredDeliveryConfig?.projectType === "LLIN-mz" - ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { - return { - ruleKey: index + 1, - delivery: {}, - attributes: item?.attributeConfig - ? item?.attributeConfig?.map((i, c) => { - if (i?.operatorValue === "IN_BETWEEN") { - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - toValue: i?.fromValue, - fromValue: i?.toValue, - }; - } - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - }; - }) - : [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: item?.productConfig - ? item?.productConfig?.map((i, c) => ({ - ...i, - })) - : [], - }; - }) - : filteredDeliveryConfig && filteredDeliveryConfig?.deliveryConfig?.[subTabIndex] - ? filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig?.map((item, index) => { - if (item) { - return { - ruleKey: index + 1, - delivery: {}, - deliveryType: item?.deliveryType, - attributes: item?.attributeConfig - ? item?.attributeConfig?.map((i, c) => { - if (i?.operatorValue === "IN_BETWEEN") { - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - toValue: i?.fromValue, - fromValue: i?.toValue, - }; - } - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - }; - }) - : [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: item?.productConfig - ? item?.productConfig?.map((i, c) => ({ - ...i, - })) - : [], - }; - } else { - return { - ruleKey: index + 1, - delivery: {}, - deliveryType: null, - attributes: [{ key: 1, attribute: null, operator: null, value: "" }], - products: [], - }; - } - }) - : [ - { - ruleKey: 1, - delivery: {}, - attributes: - filteredDeliveryConfig && filteredDeliveryConfig?.attributeConfig - ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - })) - : // : filteredDeliveryConfig?.projectType === "LLIN-mz" - // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ key: c + 1, attribute: i.attrValue, operator: null, value: "" })) - [{ key: 1, attribute: null, operator: null, value: "" }], - products: [], - }, - ], - })), - })); - } - // if no change - if (saved && saved?.length == tabs && saved?.[0]?.deliveries?.length === subTabs) { - return saved.map((i, n) => { - return { - ...i, - active: activeCycle ? (activeCycle == n + 1 ? true : false) : n === 0 ? true : false, - }; - }); - } - // if cycle number decrease - if (saved?.length > tabs) { - // const temp = saved; - saved.splice(tabs); - // return temp; - } - // if cycle number increase - if (tabs > saved?.length) { - // const temp = saved; - for (let i = saved.length + 1; i <= tabs; i++) { - const newIndex = i.toString(); - saved.push({ - cycleIndex: newIndex, - active: false, - deliveries: [...Array(subTabs || 1)].map((_, subTabIndex) => ({ - deliveryIndex: `${subTabIndex + 1}`, - active: subTabIndex === 0, - deliveryRules: - filteredDeliveryConfig?.projectType === "LLIN-mz" - ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { - return { - ruleKey: index + 1, - delivery: {}, - attributes: item?.attributeConfig - ? item?.attributeConfig?.map((i, c) => { - if (i?.operatorValue === "IN_BETWEEN") { - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - toValue: i?.fromValue, - fromValue: i?.toValue, - }; - } - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - }; - }) - : [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: item?.productConfig - ? item?.productConfig?.map((i, c) => ({ - ...i, - })) - : [], - }; - }) - : filteredDeliveryConfig && filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig - ? filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig?.map((item, index) => { - if (item) { - return { - ruleKey: index + 1, - delivery: {}, - deliveryType: item?.deliveryType, - attributes: item?.attributeConfig - ? item?.attributeConfig?.map((i, c) => { - if (i?.operatorValue === "IN_BETWEEN") { - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - toValue: i?.fromValue, - fromValue: i?.toValue, - }; - } - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - }; - }) - : [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: item?.productConfig - ? item?.productConfig?.map((i, c) => ({ - ...i, - })) - : [], - }; - } else { - return { - ruleKey: index + 1, - delivery: {}, - deliveryType: null, - attributes: [{ key: 1, attribute: null, operator: null, value: "" }], - products: [], - }; - } - }) - : [ - { - ruleKey: 1, - delivery: {}, - deliveryType: null, - attributes: - // filteredDeliveryConfig?.projectType === "MR-DN" - // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ - // key: c + 1, - // attribute: { code: i?.attrValue }, - // operator: { code: i?.operatorValue }, - // value: i?.value, - // })) - // : filteredDeliveryConfig?.projectType === "LLIN-mz" - // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ - // key: c + 1, - // attribute: i.attrValue, - // operator: null, - // value: "", - // })) - // : - [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: [], - }, - ], - })), - }); - } - // return temp; - } - // if delivery number decrease - - saved.forEach((cycle) => { - // Remove deliveries if there are more deliveries than the specified number - if (cycle.deliveries.length > subTabs) { - cycle.deliveries.splice(subTabs); - } - - // Add deliveries if there are fewer deliveries than the specified number - if (subTabs > cycle.deliveries.length) { - for (let i = cycle.deliveries.length + 1; i <= subTabs; i++) { - const newIndex = i.toString(); - cycle.deliveries.push({ - deliveryIndex: newIndex, - active: false, - deliveryRules: - filteredDeliveryConfig?.projectType === "LLIN-mz" - ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { - return { - ruleKey: index + 1, - delivery: {}, - attributes: item?.attributeConfig - ? item?.attributeConfig?.map((i, c) => { - if (i?.operatorValue === "IN_BETWEEN") { - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - toValue: i?.fromValue, - fromValue: i?.toValue, - }; - } - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - }; - }) - : [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: item?.productConfig - ? item?.productConfig?.map((i, c) => ({ - ...i, - })) - : [], - }; - }) - : [ - { - ruleKey: 1, - delivery: {}, - attributes: [{ key: 1, attribute: null, operator: null, value: "" }], - products: [], - }, - ], - }); - } - } - }); - - return saved; - // if delivery number increase - - //if no above case - }; - - // Reducer function - const campaignDataReducer = (state, action) => { - switch (action.type) { - case "GENERATE_CAMPAIGN_DATA": - return generateTabsData(action.cycle, action.deliveries); - case "UPDATE_CAMPAIGN_DATA": - const changeUpdate = state.map((i) => { - if (i.active) { - const activeDelivery = i.deliveries.find((j) => j.active === true); - if (activeDelivery) { - return { - ...i, - deliveries: i.deliveries.map((j) => ({ - ...j, - deliveryRules: j.active ? action.payload.currentDeliveryRules : j.deliveryRules, - })), - }; - } - } - return i; - }); - return changeUpdate; - case "TAB_CHANGE_UPDATE": - const temp = state.map((i) => ({ - ...i, - active: i.cycleIndex == action.payload.tabIndex ? true : false, - })); - return temp; - // return action.payload; - case "SUBTAB_CHANGE_UPDATE": - const tempSub = state.map((camp, index) => { - if (camp.active === true) { - return { - ...camp, - deliveries: camp.deliveries.map((deliver) => ({ - ...deliver, - active: deliver.deliveryIndex == action.payload.subTabIndex ? true : false, - })), - }; - } - return camp; - }); - return tempSub; - case "ADD_DELIVERY_RULE": - const updatedDeliveryRules = [ - ...action.payload.currentDeliveryRules, - { - ruleKey: action.payload.currentDeliveryRules.length + 1, - delivery: {}, - attributes: [{ key: 1, attribute: null, operator: null, value: "" }], - products: [], - }, - ]; - const updatedData = state.map((i) => { - if (i.active) { - const activeDelivery = i.deliveries.find((j) => j.active); - if (activeDelivery) { - return { - ...i, - deliveries: i.deliveries.map((j) => ({ - ...j, - deliveryRules: j.active ? updatedDeliveryRules : j.deliveryRules, - })), - }; - } - } - return i; - }); - return updatedData; - case "REMOVE_DELIVERY_RULE": - const updatedDeleted = state.map((i) => { - if (i.active) { - const activeDelivery = i.deliveries.find((j) => j.active); - const w = makeSequential( - activeDelivery.deliveryRules.filter((j) => j.ruleKey != action.payload.item.ruleKey), - "ruleKey" - ); - if (activeDelivery) { - return { - ...i, - deliveries: i.deliveries.map((j) => ({ - ...j, - deliveryRules: j.active ? w : j.deliveryRules, - })), - }; - } - } - return i; - }); - return updatedDeleted; - case "UPDATE_DELIVERY_RULE": - return action.payload; - case "ADD_ATTRIBUTE": - return action.payload; - case "REMOVE_ATTRIBUTE": - return action.payload; - case "UPDATE_ATTRIBUTE": - return action.payload; - case "ADD_PRODUCT": - const prodTemp = action.payload.productData.map((i) => ({ ...i, value: i?.value?.id, name: i?.value?.displayName })); - const updatedState = state.map((cycle) => { - if (cycle.active) { - const updatedDeliveries = cycle.deliveries.map((dd) => { - if (dd.active) { - const updatedRules = dd.deliveryRules.map((rule) => { - if (rule.ruleKey === action.payload.delivery.ruleKey) { - return { - ...rule, - products: [...rule.products, ...prodTemp], - }; - } - return rule; - }); - return { - ...dd, - deliveryRules: updatedRules, - }; - } - return dd; - }); - return { - ...cycle, - deliveries: updatedDeliveries, - }; - } - return cycle; - }); - return updatedState; - case "REMOVE_PRODUCT": - return action.payload; - case "UPDATE_PRODUCT": - return action.payload; - default: - return state; - } - }; - - const [campaignData, dispatchCampaignData] = useReducer( - campaignDataReducer, - generateTabsData(cycleData?.cycleConfgureDate?.cycle, cycleData?.cycleConfgureDate?.deliveries) - ); - const [executionCount, setExecutionCount] = useState(0); - - useEffect(() => { - dispatchCampaignData({ - type: "GENERATE_CAMPAIGN_DATA", - cycle: cycleData?.cycleConfgureDate?.cycle, - deliveries: cycleData?.cycleConfgureDate?.deliveries, - }); - }, [cycleData]); - - useEffect(() => { - onSelect("deliveryRule", campaignData); - }, [campaignData]); - - useEffect(() => { - if (executionCount < 5) { - onSelect("deliveryRule", campaignData); - setExecutionCount((prevCount) => prevCount + 1); - } - }); - - if (deliveryConfigLoading) { - return ; - } - return ( - - - - ); -} - -export default DeliverySetup; -export { CycleContext }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js deleted file mode 100644 index 2353f85fc50..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js +++ /dev/null @@ -1,102 +0,0 @@ -import React, { useEffect } from "react"; -import { Switch, useLocation } from "react-router-dom"; -import { useTranslation } from "react-i18next"; -import { PrivateRoute, AppContainer, BreadCrumb } from "@egovernments/digit-ui-react-components"; -// import CampaignHeader from "../../components/CampaignHeader"; -import SetupCampaign from "./SetupCampaign"; -import SelectingBoundaries from "../../components/SelectingBoundaries"; - -/** - * The CampaignBreadCrumb function generates breadcrumb navigation for a campaign setup page in a React - * application. - * @returns The CampaignBreadCrumb component is returning a BreadCrumb component with the specified - * crumbs array and spanStyle prop. The crumbs array contains two objects with path, content, and show - * properties for each breadcrumb item. The spanStyle prop is set to { maxWidth: "min-content" }. - */ -const CampaignBreadCrumb = ({ location, defaultPath }) => { - const { t } = useTranslation(); - const search = useLocation().search; - const pathVar = location.pathname.replace(defaultPath + "/", "").split("?")?.[0]; - - const crumbs = [ - { - path: `/${window?.contextPath}/employee`, - content: t("CAMPAIGN_HOME"), - show: true, - }, - { - path: pathVar === "my-campaign" ? "" : `/${window?.contextPath}/employee/campaign/my-campaign`, - content: t("MY_CAMPAIGN"), - show: pathVar === "my-campaign" ? true : false, - }, - { - path: pathVar === "setup-campaign" ? "" : `/${window?.contextPath}/employee/campaign/setup-campaign`, - content: t("CREATE_NEW_CAMPAIGN"), - show: pathVar === "setup-campaign" ? true : false, - }, - ]; - - return ; -}; - -/** - * The `App` function in JavaScript defines a component that handles different routes and renders - * corresponding components based on the path provided. - * @returns The `App` component is returning a JSX structure that includes a `div` with a className of - * "wbh-header-container" containing a `CampaignBreadCrumb` component and a `Switch` component. Inside - * the `Switch` component, there are several `PrivateRoute` components with different paths and - * corresponding components such as `UploadBoundaryData`, `CycleConfiguration`, `DeliveryRule`, ` - */ -const App = ({ path, BOUNDARY_HIERARCHY_TYPE }) => { - const location = useLocation(); - const UploadBoundaryData = Digit?.ComponentRegistryService?.getComponent("UploadBoundaryData"); - const CycleConfiguration = Digit?.ComponentRegistryService?.getComponent("CycleConfiguration"); - const DeliveryRule = Digit?.ComponentRegistryService?.getComponent("DeliveryRule"); - const MyCampaign = Digit?.ComponentRegistryService?.getComponent("MyCampaign"); - const CampaignSummary = Digit?.ComponentRegistryService?.getComponent("CampaignSummary"); - const Response = Digit?.ComponentRegistryService?.getComponent("Response"); - const AddProduct = Digit?.ComponentRegistryService?.getComponent("AddProduct"); - - useEffect(() => { - if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") { - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); - } - if (window.location.pathname === "/workbench-ui/employee/campaign/response") { - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); - } - return () => { - if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") { - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); - } - }; - }, []); - return ( - -
- {window?.location?.pathname === "/workbench-ui/employee/campaign/add-product" || - window?.location?.pathname === "/workbench-ui/employee/campaign/response" ? null : ( - - )} - {/* */} -
- - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - -
- ); -}; - -export default App; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js deleted file mode 100644 index 5ab880c52cf..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js +++ /dev/null @@ -1,144 +0,0 @@ -export const TourSteps = { - '/workbench-ui/employee/workbench/manage-master-data':[ - { - content: - 'Welcome to Manage Master Data screen. Here you can search and update any master data that is configured for the logged in user tenant', - target: '.manage-master-wrapper', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Select any module name where the master is present', - target: '.wbh-mdms-module-name', - disableBeacon: true, - placement: 'center', - title:"Manage Master Data" - }, - - { - content: - 'Select any master name where the master is present', - target: '.wbh-mdms-master-name', - disableBeacon: true, - placement: 'center', - title:"Manage Master Data" - }, - ], - '/workbench-ui/employee/workbench/mdms-search-v2':[ - { - content: - 'Welcome to the master data search screen. Here you can search the master data added under this master', - target: '.search-wrapper', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Select any field value and enter the text by which data can be filtered', - target: '.label-field-pair', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Filter the master data by clicking on this search by selecting any field and exact value', - target: '.search-button-wrapper', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'To add new master data under this master click on the Add Master Data button', - target: '.mdms-add-btn', - disableBeacon: true, - placement: 'auto', - title:"Manage Master Data" - }, - - ], - '/workbench-ui/employee/workbench/mdms-add-v2':[ - { - content: - 'Welcome to the master data search screen. Here you can search the master data added under this master', - target: '.field-string', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'select the Reference master data', - target: '.form-select ', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Fill all the details by clicking on the Add Master Data', - target: '.submit-bar', - disableBeacon: true, - placement: 'auto', - title:"Manage Master Data" - }, - - ], - '/workbench-ui/employee/workbench/mdms-view':[ - { - content: - 'Welcome to the master data search screen. Here you can search the master data added under this master', - target: '.action-bar-wrap', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'select the Reference master data', - target: '.menu-wrap', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - } - ], - '/workbench-ui/employee/workbench/localisation-search':[ - { - content: - 'Welcome to the master data search screen. Here you can search the master data added under this master', - target: '.search-wrapper', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Select any field value and enter the text by which data can be filtered', - target: '.label-field-pair', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Filter the master data by clicking on this search by selecting any field and exact value', - target: '.search-button-wrapper', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'To add new master data under this master click on the Add Master Data button', - target: '.mdms-add-btn', - disableBeacon: true, - placement: 'auto', - title:"Manage Master Data" - }, - - ], -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js deleted file mode 100644 index 978ea2bfd74..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js +++ /dev/null @@ -1,46 +0,0 @@ -import axios from "axios"; - -/* Fetching sheet as json object from the API , converting them into blob and downloading it. - * Way to use the function. Just import the funtion downloadExcelWithCustomName and pass the filestoreid and customName you want to download the file. - * Rest this function will take care for you and download it in your system. - * - * Eg. -> - * const handleDownload = (id, name) => { - * downloadExcelWithCustomName({fileStoreId: id, customName: name}); - * } - * - */ - -export const downloadExcelWithCustomName = ({ fileStoreId = null, customName = null }) => { - const downloadExcel = (blob, fileName) => { - const link = document.createElement("a"); - link.href = URL.createObjectURL(blob); - link.download = fileName + ".xlsx"; - document.body.append(link); - link.click(); - link.remove(); - setTimeout(() => URL.revokeObjectURL(link.href), 7000); - }; - - if (fileStoreId) { - axios - .get("/filestore/v1/files/id", { - responseType: "arraybuffer", - headers: { - "Content-Type": "application/json", - Accept: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - "auth-token": Digit.UserService.getUser()?.["access_token"], - }, - params: { - tenantId: Digit.ULBService.getCurrentTenantId(), - fileStoreId: fileStoreId, - }, - }) - .then(async (res) => { - downloadExcel( - new Blob([res.data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), - customName ? customName : "download" - ); - }); - } -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js deleted file mode 100644 index 5e308bf82f7..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import _ from "lodash"; -import { downloadExcelWithCustomName } from "./downloadExcel"; - -export default {}; -export { downloadExcelWithCustomName }; -export const PRIMARY_COLOR = "#C84C0E"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json deleted file mode 100644 index 6fcb736c4e5..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "@egovernments/digit-ui-module-hcmmicroplanning", - "version": "0.0.1", - "description": "HCM-Microplanning", - "main": "dist/index.js", - "module": "dist/index.modern.js", - "source": "src/Module.js", - "files": [ - "dist" - ], - "scripts": { - "start": "microbundle-crl watch --no-compress --format modern,cjs", - "build": "microbundle-crl --compress --no-sourcemap --format cjs", - "prepublish": "yarn build" - }, - "peerDependencies": { - "react": "17.0.2", - "react-router-dom": "5.3.0" - }, - "dependencies": { - "@cyntler/react-doc-viewer": "1.10.3", - "@egovernments/digit-ui-components": "0.0.2-beta.2", - "@egovernments/digit-ui-react-components": "1.8.2-beta.4", - "@egovernments/digit-ui-svg-components": "1.0.8", - "@rjsf/core": "5.10.0", - "@rjsf/utils": "5.10.0", - "@rjsf/validator-ajv8": "5.10.0", - "@turf/turf": "^6.5.0", - "ajv": "^8.12.0", - "axios": "^1.6.8", - "chroma-js": "^2.4.2", - "exceljs": "^4.4.0", - "focus-trap-react": "^10.2.3", - "geojson-validation": "^1.0.2", - "jszip": "^3.10.1", - "leaflet": "^1.9.4", - "react": "17.0.2", - "react-date-range": "^1.4.0", - "react-dom": "17.0.2", - "react-drag-drop-files": "^2.3.10", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-joyride": "2.5.5", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "react-select": "5.7.4", - "safe-buffer": "^5.2.1", - "shpjs": "^4.0.4", - "uuid": "^9.0.1", - "xlsx": "0.17.5" - }, - "license": "MIT", - "keywords": [ - "digit", - "egov", - "dpg", - "digit-ui", - "workbench", - "workbench-hcm", - "hcm-microplanning" - ] -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js deleted file mode 100644 index b27e7b19922..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js +++ /dev/null @@ -1,99 +0,0 @@ -import { Loader, TourProvider } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useRouteMatch } from "react-router-dom"; -import EmployeeApp from "./pages/employee"; -import { CustomisedHooks } from "./hooks"; -import { UICustomizations } from "./configs/UICustomizations"; -// import WorkbenchCard from "./components/WorkbenchCard"; -import MicroplanningCard from "./components/MicroplanningCard"; -import MicroplanDetails from "./components/MicroplanDetails"; -import { ProviderContext } from "./utils/context"; - -const MicroplanningModule = ({ stateCode, userType, tenants }) => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - const { data: BOUNDARY_HIERARCHY_TYPE } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }], { - select: (data) => { - return data?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy; - }, - }); - const moduleCode = ["Microplanning", `boundary-${BOUNDARY_HIERARCHY_TYPE}`, "hcm-admin-schemas"]; - const { path, url } = useRouteMatch(); - const language = Digit.StoreData.getCurrentLanguage(); - const { isLoading, data: store } = Digit.Services.useStore({ - stateCode, - moduleCode, - language, - }); - - if (isLoading) { - return ; - } - - return ( - - - - - - ); -}; - -const componentsToRegister = { - MicroplanningModule, - MicroplanningCard, - MicroplanDetails, - // DigitJSONForm, - // DSSCard: null, // TO HIDE THE DSS CARD IN HOME SCREEN as per workbench - // HRMSCard // Overridden the HRMS card as per workbench -}; - -const overrideHooks = () => { - Object.keys(CustomisedHooks).map((ele) => { - if (ele === "Hooks") { - Object.keys(CustomisedHooks[ele]).map((hook) => { - Object.keys(CustomisedHooks[ele][hook]).map((method) => { - setupHooks(hook, method, CustomisedHooks[ele][hook][method]); - }); - }); - } else if (ele === "Utils") { - Object.keys(CustomisedHooks[ele]).map((hook) => { - Object.keys(CustomisedHooks[ele][hook]).map((method) => { - setupHooks(hook, method, CustomisedHooks[ele][hook][method], false); - }); - }); - } else { - Object.keys(CustomisedHooks[ele]).map((method) => { - setupLibraries(ele, method, CustomisedHooks[ele][method]); - }); - } - }); -}; - -/* To Overide any existing hook we need to use similar method */ -const setupHooks = (HookName, HookFunction, method, isHook = true) => { - window.Digit = window.Digit || {}; - window.Digit[isHook ? "Hooks" : "Utils"] = window.Digit[isHook ? "Hooks" : "Utils"] || {}; - window.Digit[isHook ? "Hooks" : "Utils"][HookName] = window.Digit[isHook ? "Hooks" : "Utils"][HookName] || {}; - window.Digit[isHook ? "Hooks" : "Utils"][HookName][HookFunction] = method; -}; -/* To Overide any existing libraries we need to use similar method */ -const setupLibraries = (Library, service, method) => { - window.Digit = window.Digit || {}; - window.Digit[Library] = window.Digit[Library] || {}; - window.Digit[Library][service] = method; -}; - -/* To Overide any existing config/middlewares we need to use similar method */ -const updateCustomConfigs = () => { - setupLibraries("Customizations", "commonUiConfig", { ...window?.Digit?.Customizations?.commonUiConfig, ...UICustomizations }); -}; - -const initMicroplanningComponents = () => { - overrideHooks(); - updateCustomConfigs(); - Object.entries(componentsToRegister).forEach(([key, value]) => { - Digit.ComponentRegistryService.setComponent(key, value); - }); -}; - -export { initMicroplanningComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js deleted file mode 100644 index a358dbbedb1..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js +++ /dev/null @@ -1,61 +0,0 @@ -import { AutoRenew, Close, FileDownload } from "@egovernments/digit-ui-svg-components"; -import React, { useCallback } from "react"; -import PropTypes from "prop-types"; - -export const ButtonType1 = (props) => { - return ( -
-

{props.text}

-
- ); -}; - -ButtonType1.propTypes = { - text: PropTypes.string.isRequired, -}; - -export const ButtonType2 = (props) => { - return ( -
- {props.showDownloadIcon && ( -
- -
- )} -

{props.text}

-
- ); -}; - -ButtonType2.propTypes = { - text: PropTypes.string.isRequired, - showDownloadIcon: PropTypes.bool, -}; - -export const ModalHeading = (props) => { - return ( -

- {props.label} -

- ); -}; - -ModalHeading.propTypes = { - label: PropTypes.string.isRequired, - className: PropTypes.string, - style: PropTypes.object, -}; - -export const CloseButton = ({ clickHandler, style = {} }) => { - return ( - - ); -}; - -CloseButton.propTypes = { - clickHandler: PropTypes.func.isRequired, - style: PropTypes.object, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js deleted file mode 100644 index f2deacbd46d..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js +++ /dev/null @@ -1,41 +0,0 @@ -import React, { useEffect, useState } from "react"; - -const CustomScaleControl = ({ map }) => { - if (!map) return null; - const [scaleText, setScaleText] = useState(""); - // Function to calculate and update the scale text - const updateScale = () => { - // Calculate the scale based on the map's current zoom level - const maxWidthMeters = map.containerPointToLatLng([0, map.getSize().y]).distanceTo(map.containerPointToLatLng([100, map.getSize().y])); - const scale = maxWidthMeters / 1000; // Convert to kilometers - - // Format the scale text - const scaleTextData = scale < 1 ? `${Math.round(scale * 1000)} m` : `${Math.round(Math.round(scale.toFixed(0) / 10) * 10)} km`; - - // Update the scale text in the container element - setScaleText(scaleTextData); - }; - - // Effect to update the scale text when the map component mounts and on map zoom change - useEffect(() => { - // Update the scale text initially - updateScale(); - - // Register the map's zoom events to update the scale text - map.on("zoomend", updateScale); - - // Clean up event listener when the component unmounts - return () => { - map.off("zoomend", updateScale); - }; - }, [map]); - - return ( -
- {scaleText} - - ); -}; - -export default CustomScaleControl; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js deleted file mode 100644 index c2cf8bac4fb..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js +++ /dev/null @@ -1,607 +0,0 @@ -import React, { useState, useEffect, useCallback, Fragment, useRef } from "react"; -import { useTranslation } from "react-i18next"; -import { Trash } from "@egovernments/digit-ui-svg-components"; -import { CloseButton, ModalHeading } from "./CommonComponents"; -import { Dropdown, TextInput, Toast } from "@egovernments/digit-ui-components"; -import { useMyContext } from "../utils/context"; -import { tourSteps } from "../configs/tourSteps"; -import { v4 as uuidv4 } from "uuid"; -import { PlusWithSurroundingCircle } from "../icons/Svg"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; -import { Button, Modal } from "@egovernments/digit-ui-react-components"; -const page = "hypothesis"; - -const Hypothesis = ({ - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - setToast, -}) => { - const { t } = useTranslation(); - - // States - const [editable, setEditable] = useState(true); - const [modal, setModalState] = useState("none"); - const [assumptions, setAssumptions] = useState([]); - const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); - const [itemForDeletion, setItemForDeletion] = useState(); - const [exampleOption, setExampleOption] = useState(""); - // const [toast, setToast] = useState(); - const [autofillHypothesis, setAutofillHypothesis] = useState([]); - const { state, dispatch } = useMyContext(); - const [orignalHypothesisCount, setOrignalHypothesisCount] = useState(0); - - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - const setModal = (modalString) => { - const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); - elements.forEach((element) => { - element.classList.toggle("popup-wrap-rest-unfocus-active"); - }); - setModalState(modalString); - }; - - // UseEffect to extract data on first render - useEffect(() => { - if (pages) { - const previouspage = pages[currentPage?.id - 1]; - if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); - else setEditable(true); - } - if (microplanData?.hypothesis) { - const temp = microplanData?.hypothesis; - setAssumptions(temp); - } - - fetchDataAndUpdateState(); - }, []); - - const fetchDataAndUpdateState = useCallback(() => { - const hypothesisAssumptions = state?.HypothesisAssumptions || []; - const temp = hypothesisAssumptions.find((item) => item.campaignType === campaignType); - if (!temp?.assumptions) return; - - const hypothesisAssumptionsList = Array.isArray(temp.assumptions) ? temp.assumptions : []; - setOrignalHypothesisCount(hypothesisAssumptionsList.length); - setExampleOption(hypothesisAssumptionsList.length !== 0 ? hypothesisAssumptionsList[0] : ""); - - const currentHypothesis = microplanData?.hypothesis || assumptions; - const newAssumptions = setAutofillHypothesisData(hypothesisAssumptionsList, currentHypothesis, setAssumptions); - - const newHypothesislist = filterHypothesisList( - newAssumptions.length !== 0 ? newAssumptions : microplanData.hypothesis, - hypothesisAssumptionsList - ); - setHypothesisAssumptionsList(newHypothesislist); - }, [campaignType, microplanData, state, assumptions, setAssumptions]); - - // UseEffect for checking completeness of data before moveing to next section - useEffect(() => { - if (!assumptions || checkDataCompletion !== "true" || !setCheckDataCompletion) return; - // uncomment to activate data change save check - // if (!microplanData?.hypothesis || !_.isEqual(assumptions, microplanData.hypothesis)) setModal("data-change-check"); - // else - updateData(true); - }, [checkDataCompletion]); - - // UseEffect to store current data - useEffect(() => { - if (!assumptions || !setMicroplanData) return; - setMicroplanData((previous) => ({ ...previous, hypothesis: assumptions })); - }, [assumptions]); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - // if (modal === "upload-guidelines") - setCheckDataCompletion("false"); - setModal("none"); - } - }; - - // check if data has changed or not - const updateData = useCallback( - (check) => { - if (!assumptions || !setMicroplanData) return; - if (check) { - if (assumptions.some((item) => item.active && parseFloat(item.value) === 0)) { - setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") }); - setCheckDataCompletion("false"); - return; - } - let newAssumptions = assumptions.map((item) => { - if (parseFloat(item.value) === 0) { - return { ...item, value: 0.01 }; - } - return item; - }); - setMicroplanData((previous) => ({ ...previous, hypothesis: newAssumptions })); - setAssumptions(newAssumptions); - let checkValid = validateAssumptions(assumptions); - checkValid = checkValid && assumptions.filter((subItem) => subItem?.active).length !== 0; - if (checkValid) setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } else { - let checkValid = microplanData?.hypothesis?.every((item) => Object.values(item).every((data) => data !== "")); - checkValid = checkValid && assumptions.length !== 0; - if (checkValid) setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } - }, - [assumptions, setMicroplanData, microplanData, setCheckDataCompletion] - ); - - const validateAssumptions = useCallback((assumptions) => { - return assumptions.filter((item) => item?.active).every((item) => Object.values(item).every((data) => data !== "")) && assumptions.length !== 0; - }, []); - - const cancelUpdateData = useCallback(() => { - setCheckDataCompletion("false"); - setModal("none"); - }, [setCheckDataCompletion, setModal]); - - const closeModal = useCallback(() => { - setModal("none"); - }, []); - - // Function to Delete an assumption - const deleteAssumptionHandlerCallback = useCallback(() => { - deleteAssumptionHandler(itemForDeletion, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, setToast, t); - closeModal(); - }, [itemForDeletion, deleteAssumptionHandler, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, closeModal, setToast, t]); - - const sectionClass = `jk-header-btn-wrapper hypothesis-section ${editable ? "" : "non-editable-component"} popup-wrap-rest-unfocus `; - - return ( - <> -
-
- {/* NonInterractable Section */} - - {/* Interractable Section that includes the example as well as the assumptions */} - -
-
-
- {modal === "delete-conformation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={deleteAssumptionHandlerCallback} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={closeModal} - > -
-

{t("HYPOTHESIS_INSTRUCTIONS_DELETE_ENTRY_CONFIRMATION")}

-
-
- )} -
- - ); -}; - -// Function to add a new assumption -const addAssumptionsHandler = (setAssumptions) => { - const uuid = uuidv4(); - setAssumptions((previous) => [ - ...previous, - { - id: uuid, - // previous.length ? previous[previous.length - 1].id + 1 : 0, - key: "", - value: "", - active: true, - }, - ]); -}; - -// Defination for NonInterractable Section -const NonInterractableSection = React.memo(({ t }) => { - return ( -
-

{t("HEADING_HYPOTHESIS")}

-

{t("INSTRUCTION_HYPOTHESIS")}

-
- ); -}); - -// Defination for NonInterractable Section -const InterractableSection = React.memo( - ({ assumptions, setAssumptions, hypothesisAssumptionsList, setHypothesisAssumptionsList, setModal, setItemForDeletion, exampleOption, t }) => { - const itemRefs = useRef([]); - const [expandedIndex, setExpandedIndex] = useState(null); - const scrollContainerRef = useRef(null); - const [renderCycle, setRenderCycle] = useState(0); - - useEffect(() => { - if (expandedIndex !== null) { - setRenderCycle(0); // Reset render cycle count when expandedIndex changes - } - }, [expandedIndex]); - - useEffect(() => { - // Scroll to the expanded item after the state has updated and the DOM has re-rendered - if (renderCycle < 2) { - setRenderCycle((prev) => prev + 1); // Increment render cycle count - } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { - try { - const parentElement = itemRefs.current[expandedIndex]; - const childElement = itemRefs.current[expandedIndex].children[1]; - - if (parentElement) { - const scrollContainer = scrollContainerRef.current; - const parentRect = parentElement.getBoundingClientRect(); - const containerRect = scrollContainer.getBoundingClientRect(); - - // Calculate the offset from the top of the container - const offset = parentRect.top - containerRect.top; - - // Scroll the container - scrollContainer.scrollTo({ - top: scrollContainer.scrollTop + offset - 10, - behavior: "smooth", - }); - } - - if (childElement) { - childElement.focus(); - } - } catch (error) { - console.error("Error scrolling to element:", error); - } - } - }, [renderCycle, expandedIndex]); - - useEffect(() => { - if (expandedIndex !== null) { - const observer = new MutationObserver(() => { - setRenderCycle((prev) => prev + 1); // Trigger render cycle when the DOM changes - }); - - if (itemRefs.current[expandedIndex]) { - observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); - } - - return () => observer.disconnect(); - } - }, [expandedIndex]); - - const toggleExpand = (index) => { - setExpandedIndex(index === expandedIndex ? null : index); - }; - - // Handler for deleting an assumption on conformation - const deleteHandler = useCallback( - (item) => { - setModal("delete-conformation"); - setItemForDeletion(item); - }, - [setModal, setItemForDeletion] - ); - - return ( -
- -
-
-
-

{t("KEY")}

-
-
-

{t("VALUE")}

-
-
- -
-
- {assumptions - ?.filter((item) => item.active) - ?.map((item, index) => ( -
item.active)?.length - 1 ? "last-container" : "" - } `} - > -
{ - itemRefs.current[index] = el; - }} - onClick={() => { - toggleExpand(index); - }} - > - -
-
- -
-
- ))} -
-
- ); - } -); - -const Example = ({ exampleOption, t }) => { - return ( -
-

{t("EXAMPLE")}

-
-
-

{t("KEY")}

- -

{t("HYPOTHESIS_KEY_HELP_TEXT")}

-
-
-

{t("VALUE")}

- -

{t("HYPOTHESIS_VALUE_HELP_TEXT")}

-
-
-
- ); -}; - -const deleteAssumptionHandler = (item, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, setToast, t) => { - let add = true; - setAssumptions((previous) => { - if (!previous.length) return []; - if (previous.filter((item) => item.active)?.length <= 1) { - setToast({ state: "error", message: t("ERROR_CANNOT_DELETE_LAST_HYPOTHESIS") }); - add = false; - return previous; - } - // const filteredData = previous.filter((data) => data.id !== item.id); - const deletionElementIndex = previous.findIndex((data) => data.id === item.id); - const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data)); - return filteredData || []; - }); - if (add && item && item.key) - setHypothesisAssumptionsList((previous) => { - if (!previous.includes(item.key)) return [...previous, item.key]; - return previous; // Return previous array if key already exists - }); - setItemForDeletion(); -}; - -const Select = React.memo(({ item, assumptions, setAssumptions, disabled = false, options, setOptions, t }) => { - const [selected, setSelected] = useState(); - const [filteredOptions, setFilteredOptions] = useState([]); - - useEffect(() => { - if (item?.key) setSelected({ code: item.key }); - }, [item]); - - useEffect(() => { - if (!options) return; - const filteredOptions = options.length ? options : []; - if (item?.key && !filteredOptions.includes(item.key)) { - setFilteredOptions([item.key, ...filteredOptions]); - } else setFilteredOptions(filteredOptions); - }, [options]); - - const selectChangeHandler = useCallback( - (e) => { - const existingEntry = assumptions.find((item) => item?.active && item?.key === e?.code); - if (existingEntry) return; - const newDataSegment = { - ...item, - id: item.id, - key: e?.code, - value: item.value, - }; - setAssumptions((previous) => { - const filteredAssumptionsList = previous.map((data) => { - if (data.id === item.id) return newDataSegment; - return data; - }); - return filteredAssumptionsList; - }); - - setOptions((previous) => { - let newOptions = previous.filter((item) => item !== e?.code); - if (selected && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code); - return newOptions; - }); - }, - [assumptions, item, selected, setAssumptions, setOptions] - ); - - return ( - ({ code: item }))} - selected={selected} - optionKey="code" - select={selectChangeHandler} - // style={{ width: "100%", backgroundColor: "rgb(0,0,0,0)", position:"sticky" }} - optionCardStyles={{ position: "absolute" }} - placeholder={t("SELECT_OPTION")} - showToolTip={true} - /> - ); -}); - -const Input = React.memo(({ item, setAssumptions, t, disabled = false }) => { - const [inputValue, setInputValue] = useState(""); - - useEffect(() => { - if (item) setInputValue(item.value); - }, [item]); - - const inputChangeHandler = useCallback( - (e) => { - if (e.target.value.includes("+") || e.target.value.includes("e")) return; - if ((e.target.value < 0 || e.target.value > 10000000000) && e.target.value !== "") return; - let value; - const decimalIndex = e.target.value.indexOf("."); - if (decimalIndex !== -1) { - const numDecimals = e.target.value.length - decimalIndex - 1; - value = e.target.value; - if (numDecimals <= 2) { - value = e.target.value; - } else if (numDecimals > 2) { - value = value.substring(0, decimalIndex + 3); - } - } else value = Number.parseFloat(e.target.value); - - setInputValue(!Number.isNaN(value) ? value : ""); - const newDataSegment = { - ...item, - id: item.id, - key: item.key, - value: !Number.isNaN(value) ? value : "", - }; - setAssumptions((previous) => { - const filteredAssumptionsList = previous.map((data) => { - if (data.id === item.id) { - return newDataSegment; - } - return data; - }); - return filteredAssumptionsList; - }); - }, - [item, setAssumptions] - ); - - return ( - - ); -}); - -const setAutofillHypothesisData = (autofillHypothesis, assumptions, setAssumptions) => { - if (assumptions?.length !== 0) return []; - let newAssumptions = []; - for (let i in autofillHypothesis) { - const uuid = uuidv4(); - newAssumptions.push({ - id: uuid, - key: autofillHypothesis[Number(i)], - value: "", - active: true, - }); - } - setAssumptions(newAssumptions); - return newAssumptions; -}; - -const filterHypothesisList = (assumptions, hypothesisList) => { - let alreadySelectedHypothesis = assumptions.filter((item) => item?.active).map((item) => item?.key) || []; - return hypothesisList.filter((item) => !alreadySelectedHypothesis.includes(item)); -}; - -export default Hypothesis; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js deleted file mode 100644 index 23bbef8ae29..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js +++ /dev/null @@ -1,113 +0,0 @@ -import { Button, DownloadIcon, SVG } from "@egovernments/digit-ui-react-components"; -import React, { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; - -export const JsonPreviewInExcelForm = (props) => { - const { t } = useTranslation(); - const sheetsData = props?.sheetsData; - const [currentSheetName, setCurrentSheetName] = useState(Object.keys(sheetsData).length > 0 ? Object.keys(sheetsData)[0] : undefined); - return ( -
-
-
-
- {props?.errorLocationObject?.[currentSheetName] &&

{t("USER_DIRECTIONS_FOR_ERROR_MESSAGE")}

} - {/* {Object.entries(sheetsData).map(([sheetName, sheetData], index) => ( */} -
- - - - {sheetsData?.[currentSheetName]?.[0] - ?.filter((header) => header) - .map((header) => ( - - ))} - - - - {sheetsData?.[currentSheetName]?.slice(1).map((rowData, rowIndex) => ( - - {Object.values(sheetsData?.[currentSheetName]?.[0])?.map((_, cellIndex) => { - const headerName = sheetsData?.[currentSheetName]?.[0]?.[cellIndex]; - const error = headerName ? props?.errorLocationObject?.[currentSheetName]?.[rowIndex]?.[headerName] : undefined; - let convertedError; - if (typeof error?.[0] === "object") { - let { error: actualError, ...otherProperties } = error[0]; - convertedError = t(actualError, otherProperties?.values); - } else { - convertedError = t(error); - } - const rowHasError = - typeof props?.errorLocationObject?.[currentSheetName]?.[rowIndex] === "object" - ? Object.keys(props?.errorLocationObject?.[currentSheetName]?.[rowIndex]).length !== 0 - : undefined; - return ( - - ); - })} - - ))} - -
{t(header)}
- {cellIndex === 0 && rowHasError &&
} - - {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : ""} -
-
-
- {Object.entries(sheetsData).map(([sheetName, sheetData], index) => ( - - ))} -
- {/* ))} */} -
-
- ); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js deleted file mode 100644 index 75f953c8804..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js +++ /dev/null @@ -1,445 +0,0 @@ -// Importing necessary modules -import { Card, Header } from "@egovernments/digit-ui-components"; -import L from "leaflet"; -import "leaflet/dist/leaflet.css"; -import React, { useCallback, useEffect, useRef, useState, Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import ZoomControl from "./ZoomControl"; -import CustomScaleControl from "./CustomScaleControl"; -import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; -import { LoaderWithGap } from "@egovernments/digit-ui-react-components"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { - MapFilterIndex, - MapChoroplethIndex, - ChoroplethSelection, - FilterSection, - BoundarySelection, - BaseMapSwitcher, -} from "./MappingHelperComponents"; -import { - enableMapInteractions, - disableMapInteractions, - removeAllLayers, - filterBoundarySelection, - findBounds, - addGeojsonToMap, - addFilterProperties, - addChoroplethProperties, - prepareGeojson, - extractGeoData, -} from "../utils/mappingUtils"; - -const page = "mapping"; - -// Mapping component definition -const Mapping = ({ - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - setToast, - ...props -}) => { - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - - // request body for boundary hierarchy api - var reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - // hierarchyType: "Microplan", - hierarchyType: campaignData?.hierarchyType, - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return ( - data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ - ...item, - parentBoundaryType: item?.parentBoundaryType - ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` - : null, - boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, - })) || {} - ); - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); - // request body for boundary hierarchy api - var reqCriteria = { - url: `/boundary-service/boundary/_search`, - params: { codes: Digit.ULBService.getCurrentTenantId(), tenantId: Digit.ULBService.getCurrentTenantId() }, - body: {}, - config: { - select: (data) => { - return data?.Boundary || {}; - }, - }, - }; - const { isLoading: isBoundaryLoading, data: Boundary } = Digit.Hooks.useCustomAPIHook(reqCriteria); - - // Setting up state variables - const [editable, setEditable] = useState(true); - const { t } = useTranslation(); - var [map, setMap] = useState(null); - var [_mapNode, set__mapNode] = useState("map"); - const [layers, setLayer] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [filterDataOrigin, setFilterDataOrigin] = useState({}); - const [dataAvailability, setDataAvailability] = useState("true"); - // const [toast, setToast] = useState(); - const [baseMaps, setBaseMaps] = useState({}); - const [selectedBaseMap, setSelectedBaseMap] = useState({}); - const [selectedBaseMapName, setSelectedBaseMapName] = useState(""); - const [showBaseMapSelector, setShowBaseMapSelector] = useState(false); - const [boundaryData, setBoundaryData] = useState({}); // State for boundary data - const [filterData, setFilterData] = useState({}); // State for facility data - const [boundarySelections, setBoundarySelections] = useState({}); - const [isboundarySelectionSelected, setIsboundarySelectionSelected] = useState(false); - const { state, dispatch } = useMyContext(); - const [filterPropertyNames, setFilterPropertyNames] = useState(); - const [filterProperties, setFilterProperties] = useState(); - const [showFilterOptions, setShowFilterOptions] = useState(false); - const [filterSelections, setFilterSelections] = useState([]); - const [choroplethProperties, setChoroplethProperties] = useState([]); - const [showChoroplethOptions, setShowChoroplethOptions] = useState(false); - const [choroplethProperty, setChoroplethProperty] = useState(); - const [dataCompleteness, setDataCompleteness] = useState(); - const basemapRef = useRef(); - const filterBoundaryRef = useRef(); - const showChoroplethOptionRef = useRef(); - const showFilterOptionRef = useRef(); - const [loader, setLoader] = useState(false); - - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - // Effect to initialize map when data is fetched - useEffect(() => { - if (!state || !Boundary) return; - const UIConfiguration = state?.UIConfiguration; - if (UIConfiguration) { - const filterDataOriginList = UIConfiguration.find((item) => item.name === "mapping"); - setFilterDataOrigin(filterDataOriginList); - } - const BaseMapLayers = state?.BaseMapLayers; - const schemas = state?.Schemas; - if (schemas) setValidationSchemas(schemas); - if (!BaseMapLayers || (BaseMapLayers && BaseMapLayers.length === 0)) return; - let baseMaps = {}; - let defaultBaseMap = undefined; - BaseMapLayers.forEach((item) => { - if (item.url) { - const layer = L.tileLayer(item.url, { - minZoom: item?.minZoom, - maxZoom: item?.maxZoom, - attribution: item?.attribution, - }); - baseMaps[item?.name] = { - metadata: item, - layer, - }; - if (!defaultBaseMap) - defaultBaseMap = { - name: item?.name, - layer, - }; - } - }); - setSelectedBaseMapName(defaultBaseMap?.name); - setBaseMaps(baseMaps); - if (!map) { - init(_mapNode, defaultBaseMap, Boundary); - } - }, [Boundary]); - - useEffect(() => { - if (map && filterDataOrigin && Object.keys(filterDataOrigin).length !== 0) { - setLoader("LOADING"); - // Check if all the data is present or not, if it is then extract it in a format that can be used for mapping and other mapping related operations - extractGeoData( - campaignType, - microplanData, - filterDataOrigin, - validationSchemas, - setToast, - setDataAvailability, - hierarchy, - setBoundaryData, - setFilterData, - setFilterProperties, - setFilterSelections, - setFilterPropertyNames, - state, - setChoroplethProperties, - setDataCompleteness, - t - ); - setLoader(false); - } - }, [filterDataOrigin, hierarchy]); - - // Function to initialize map - const init = (id, defaultBaseMap, Boundary) => { - if (map !== null) return; - - // let bounds = findBounds(Boundary); - - let mapConfig = { - center: [0, 0], - zoomControl: false, - zoom: 3, - scrollwheel: true, - minZoom: 3, - }; - - let map_i = L.map(id, mapConfig); - var verticalBounds = L.latLngBounds(L.latLng(-90, -170), L.latLng(85, 190)); - map_i.on("drag", () => { - map_i.panInsideBounds(verticalBounds, { animate: true }); - }); - map_i.on("zoom", () => { - map_i.panInsideBounds(verticalBounds, { animate: true }); - }); - const defaultBaseLayer = defaultBaseMap?.layer.addTo(map_i); - // if (bounds) map_i.fitBounds(bounds); - setSelectedBaseMap(defaultBaseLayer); - setMap(map_i); - }; - - const handleBaseMapToggle = (newBaseMap) => { - if (map) { - const currentBaseLayer = selectedBaseMap; - if (currentBaseLayer) { - currentBaseLayer.remove(); - } - const newBaseLayer = baseMaps[newBaseMap].layer.addTo(map); - // Add the new base layer to the bottom of the layer stack - newBaseLayer.addTo(map); - - // Update the baseLayer state - setSelectedBaseMap(newBaseLayer); - setSelectedBaseMapName(newBaseMap); - } - }; - - // showing selected boundary data - useEffect(() => { - if (!boundarySelections && !choroplethProperty && !filterSelections) return; - setLoader("LOADING"); - try { - removeAllLayers(map, layers); - const { filteredSelection, childrenList } = filterBoundarySelection(boundaryData, boundarySelections); - let newLayer = []; - let addOn = { - fillColor: "rgba(255, 107, 43, 0)", - weight: 3.5, - opacity: 1, - color: "rgba(176, 176, 176, 1)", - fillOpacity: 0, - fill: "rgb(4,136,219,1)", - child: !childrenList || childrenList.length === 0, // so that this layer also has mounse in and mouse out events - }; - let geojsonsBase = prepareGeojson(boundaryData, "ALL", addOn); - if (geojsonsBase) { - let baseLayer = addGeojsonToMap(map, geojsonsBase, t); - if (baseLayer) newLayer.push(baseLayer); - let bounds = findBounds(geojsonsBase); - if (bounds) map.fitBounds(bounds); - } - - addOn = { - fillColor: "rgba(255, 107, 43, 1)", - weight: 2.5, - opacity: 1, - color: "rgba(255, 255, 255, 1)", - fillOpacity: 0.22, - fill: "rgb(4,136,219)", - }; - - let geojsonLayer; - if (choroplethProperty) { - if (dataCompleteness === "partial" || dataCompleteness === "false" || dataCompleteness === undefined) { - setToast({ - state: "warning", - message: t("DISPLAYING_DATA_ONLY_FOR_UPLOADED_BOUNDARIES"), - }); - } - - let choroplethGeojson = prepareGeojson(boundaryData, "ALL", { ...addOn, child: true, fillColor: "rgb(0,0,0,0)" }) || []; - if (choroplethGeojson && choroplethGeojson.length !== 0) - choroplethGeojson = addChoroplethProperties(choroplethGeojson, choroplethProperty, filteredSelection); - geojsonLayer = addGeojsonToMap(map, choroplethGeojson, t); - if (geojsonLayer) { - newLayer.push(geojsonLayer); - } - } - geojsonLayer = null; - const geojsons = prepareGeojson(boundaryData, filteredSelection, addOn); - if (geojsons && geojsons.length > 0) { - geojsonLayer = addGeojsonToMap(map, geojsons, t); - newLayer.push(geojsonLayer); - let bounds = findBounds(geojsons); - if (bounds) map.fitBounds(bounds); - } - - const childrenGeojson = prepareGeojson(boundaryData, childrenList, { ...addOn, opacity: 0, fillOpacity: 0, child: true }); - let childrenGeojsonLayer = addGeojsonToMap(map, childrenGeojson, t); - if (childrenGeojsonLayer) newLayer.push(childrenGeojsonLayer); - - //filters - const filterGeojsons = prepareGeojson(filterData, filteredSelection && filteredSelection.length !== 0 ? filteredSelection : "ALL", addOn); - const filterGeojsonWithProperties = addFilterProperties(filterGeojsons, filterSelections, filterPropertyNames, state?.MapFilters); - let filterGeojsonLayer = addGeojsonToMap(map, filterGeojsonWithProperties, t); - if (filterGeojsonLayer) newLayer.push(filterGeojsonLayer); - - setLayer(newLayer); - } catch (error) { - console.error("Error while adding geojson to map: ", error.message); - } - setLoader(false); - }, [boundarySelections, choroplethProperty, filterSelections]); - - const handleOutsideClickAndSubmitSimultaneously = useCallback(() => { - if (isboundarySelectionSelected) setIsboundarySelectionSelected(false); - if (showBaseMapSelector) setShowBaseMapSelector(false); - if (showFilterOptions) setShowFilterOptions(false); - if (showChoroplethOptions) setShowChoroplethOptions(false); - }, [ - isboundarySelectionSelected, - showBaseMapSelector, - showFilterOptions, - showChoroplethOptions, - setIsboundarySelectionSelected, - setShowBaseMapSelector, - setShowFilterOptions, - setShowChoroplethOptions, - ]); - Digit?.Hooks.useClickOutside(filterBoundaryRef, handleOutsideClickAndSubmitSimultaneously, isboundarySelectionSelected, { capture: true }); - Digit?.Hooks.useClickOutside(basemapRef, handleOutsideClickAndSubmitSimultaneously, showBaseMapSelector, { capture: true }); - Digit?.Hooks.useClickOutside(showFilterOptionRef, handleOutsideClickAndSubmitSimultaneously, showFilterOptions, { capture: true }); - Digit?.Hooks.useClickOutside(showChoroplethOptionRef, handleOutsideClickAndSubmitSimultaneously, showChoroplethOptions, { capture: true }); - - // function to stop mouse event propogation from custom comopents to leaflet map - const handleMouseDownAndScroll = (event) => { - event?.stopPropagation(); - disableMapInteractions(map); - }; - - const handleMouseUpAndScroll = (event) => { - enableMapInteractions(map); - }; - useEffect(() => { - if (isboundarySelectionSelected || showBaseMapSelector || showFilterOptions || showChoroplethOptions) handleMouseDownAndScroll(); - else handleMouseUpAndScroll(); - }, [isboundarySelectionSelected, showBaseMapSelector, showFilterOptions, showChoroplethOptions, choroplethProperty, filterPropertyNames]); - - // Rendering component - return ( -
-
{t("MAPPING")}
- - - {/* Container for map */} - -
-
-
- -
- {filterProperties && Object.keys(filterProperties).length !== 0 && ( - - )} - -
- -
- -
- {DigitSvgs.NorthArrow && } -
- -
- -
- {filterSelections && filterSelections.length > 0 && ( - - )} - {choroplethProperty && } -
-
-
-
- {loader && } -
- ); -}; - -// Exporting Mapping component -export default Mapping; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js deleted file mode 100644 index 9cea19a943f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js +++ /dev/null @@ -1,513 +0,0 @@ -// Importing necessary modules -import { Card, CardLabel, MultiSelectDropdown, Button, CheckBox, RadioButtons } from "@egovernments/digit-ui-components"; -import "leaflet/dist/leaflet.css"; -import React, { memo, useCallback, useEffect, useMemo, useRef, useState, Fragment } from "react"; -import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; -import { CardSectionHeader, InfoIconOutline, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import { fetchDropdownValues } from "../utils/processHierarchyAndData"; -import { MapChoroplethGradientColors, PRIMARY_THEME_COLOR } from "../configs/constants"; -import { ModalHeading } from "./CommonComponents"; -import * as MicroplanIconCollection from "../icons/Svg"; -import { generatePreviewUrl } from "../utils/mappingUtils"; - -const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs }; - -export function checkTruthyKeys(obj) { - for (let key in obj) { - if (Object.hasOwn(obj, key)) { - if (obj[key] && !(Array.isArray(obj[key]) && obj[key].length === 0)) { - return true; - } - } - } - return false; -} - -export const MapFilterIndex = ({ filterSelections, MapFilters, t }) => { - return ( -
- {filterSelections && filterSelections.length > 0 ? ( - <> - {filterSelections.map((item, index) => ( - //
- - //

{t(item)}

- //
- ))} - - ) : ( - "" - )} -
- ); -}; - -// Function to create the gradient from the colors array for choropleth index -export const MapChoroplethIndex = ({ t, choroplethProperty }) => { - const createGradientString = (colors) => { - return colors.map((color) => `${color.color} ${color.percent}%`).join(", "); - }; - - const gradientString = createGradientString(MapChoroplethGradientColors); - const gradientStyle = { - background: `linear-gradient(to right, ${gradientString})`, - }; - - return ( -
-
-

0%

-
-

100%

-
-

{t(choroplethProperty)}

-
- ); -}; - -export const FilterItemBuilder = ({ item, MapFilters, t }) => { - let temp = MapFilters?.find((e) => e?.name === item)?.icon?.index; - let DynamicIcon = IconCollection?.[temp]; - // let icon; - // if (typeof DynamicIcon === "function") icon = DynamicIcon({}); - return DynamicIcon && typeof DynamicIcon === "function" ? ( -
- -

{t(item)}

-
- ) : ( - //
- "" - ); -}; - -export const ChoroplethSelection = memo( - ({ - choroplethProperties, - showChoroplethOptions, - showChoroplethOptionRef, - setShowChoroplethOptions, - choroplethProperty, - setChoroplethProperty, - t, - }) => { - const handleChange = useCallback( - (value) => { - setChoroplethProperty(value?.code); - }, - [choroplethProperties] - ); - - return ( -
-
setShowChoroplethOptions((previous) => !previous)} - onKeyUp={() => setShowChoroplethOptions((previous) => !previous)} - tabIndex={0} - > -

{t("VISUALIZATIONS")}

-
- {DigitSvgs.FilterAlt && } -
-
- {showChoroplethOptions && ( -
-
- ({ name: item, id: item, code: item }))} - optionsKey="name" - onSelect={handleChange} - selectedOption={choroplethProperty} - /> -
-
- )} -
- ); - } -); - -export const FilterSection = memo( - ({ filterProperties, showFilterOptionRef, showFilterOptions, setShowFilterOptions, filterSelections, setFilterSelections, t }) => { - const handleChange = useCallback( - (e, item) => { - let tempFilterSelections = [...filterSelections]; // Clone the array to avoid mutating state directly - if (filterSelections.includes(item)) { - tempFilterSelections = tempFilterSelections.filter((element) => element !== item); - } else { - tempFilterSelections.push(item); - } - setFilterSelections(tempFilterSelections); - }, - [filterSelections] - ); - - return ( -
-
setShowFilterOptions((previous) => !previous)} - onKeyUp={() => setShowFilterOptions((previous) => !previous)} - tabIndex={0} - > -

{t("FILTERS")}

-
- {DigitSvgs.FilterAlt && } -
-
- {showFilterOptions && ( -
-
- {filterProperties.map((item) => ( -
- handleChange(e, item)} - label={t(item)} - checked={!!filterSelections.includes(item)} - mainClassName="mainClassName" - labelClassName="labelClassName" - inputWrapperClassName="inputWrapperClassName" - inputClassName="inputClassName" - inputIconClassname="inputIconClassname" - iconFill={PRIMARY_THEME_COLOR} - onLabelClick={(e) => handleChange(e, item)} - /> -
- ))} -
-
- )} -
- ); - } -); - -export const BoundarySelection = memo( - ({ - boundarySelections, - setBoundarySelections, - boundaryData, - hierarchy, - filterBoundaryRef, - isboundarySelectionSelected, - setIsboundarySelectionSelected, - t, - }) => { - const [processedHierarchy, setProcessedHierarchy] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [showConfirmationModal, setShowConformationModal] = useState(false); - const itemRefs = useRef([]); - const [expandedIndex, setExpandedIndex] = useState(null); - const scrollContainerRef = useRef(null); - const [changedBoundaryType, setChangedBoundaryType] = useState(""); - const [isScrollable, setIsScrollable] = useState(false); - - useEffect(() => { - // Scroll to the expanded item's child element after the state has updated and the DOM has re-rendered - if (expandedIndex !== null && itemRefs.current[expandedIndex]) { - // Use a timeout to ensure the DOM has updated - setTimeout(() => { - const childElement = itemRefs.current[expandedIndex].children[0]; // Assuming child content is the second child - // if (childElement) { - // childElement.scrollIntoView({ behavior: 'smooth' }); - // } - if (childElement) { - const scrollContainer = scrollContainerRef.current; - const childElementBound = childElement.getBoundingClientRect(); - const containerRect = scrollContainer.getBoundingClientRect(); - - // Calculate the offset from the top of the container - const offset = childElementBound.top - containerRect.top; - - // Scroll the container - scrollContainer.scrollTo({ - top: scrollContainer.scrollTop + offset - 10, - behavior: "smooth", - }); - } - }, 0); - } - }, [expandedIndex]); - - const toggleExpand = (index) => { - setExpandedIndex(index === expandedIndex ? null : index); - }; - - // Filtering out dropdown values - useEffect(() => { - if (!boundaryData || !hierarchy) return; - const processedHierarchyTemp = fetchDropdownValues( - boundaryData, - processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, - boundarySelections, - changedBoundaryType - ); - setProcessedHierarchy(processedHierarchyTemp); - setIsLoading(false); - }, [boundaryData, hierarchy, boundarySelections]); - - const handleClearAll = () => { - setShowConformationModal(true); - }; - - const handleSubmitConfModal = () => { - setBoundarySelections({}); - setShowConformationModal(false); - }; - - const handleCancelConfModal = () => { - setShowConformationModal(false); - }; - - const checkScrollbar = () => { - if (scrollContainerRef.current) { - setIsScrollable(scrollContainerRef.current.scrollHeight > scrollContainerRef.current.clientHeight); - } - }; - - useEffect(() => { - // Initial check - checkScrollbar(); - - // Check on resize - window.addEventListener("resize", checkScrollbar); - - // Cleanup event listeners on component unmount - return () => { - window.removeEventListener("resize", checkScrollbar); - }; - }, [isboundarySelectionSelected]); - - useEffect(() => { - const content = scrollContainerRef.current; - content.addEventListener("scroll", checkScrollbar); - - return () => { - content.removeEventListener("scroll", checkScrollbar); - }; - }, [scrollContainerRef]); - - return ( -
- {isLoading && } -
- ); - } -); - -export const BaseMapSwitcher = ({ - baseMaps, - showBaseMapSelector, - setShowBaseMapSelector, - handleBaseMapToggle, - selectedBaseMapName, - basemapRef, - t, -}) => { - if (!baseMaps) return null; - return ( -
-
setShowBaseMapSelector((previous) => !previous)} - onKeyUp={() => setShowBaseMapSelector((previous) => !previous)} - tabIndex={0} - > -

{t("LAYERS")}

-
{DigitSvgs.Layers && }
-
-
- {showBaseMapSelector && ( -
- {Object.entries(baseMaps).map(([name, baseMap], index) => { - return ( -
- {t("ERROR_LOADING_BASE_MAP")} handleBaseMapToggle(name)} - /> -

{t(name)}

-
- ); - })} -
- )} -
-
- ); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js deleted file mode 100644 index b6a2fb9a205..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js +++ /dev/null @@ -1,111 +0,0 @@ -import React, { memo } from "react"; -import { ActionBar, ArrowForward, Banner } from "@egovernments/digit-ui-components"; -import { useTranslation } from "react-i18next"; -import { ArrowBack, FileDownload } from "@egovernments/digit-ui-svg-components"; -import { convertJsonToXlsx, writeWorkbookToBuffer } from "../utils/jsonToExcelBlob"; -import { Button } from "@egovernments/digit-ui-react-components"; -import { useHistory } from "react-router-dom"; -import { Link } from "react-router-dom/cjs/react-router-dom.min"; -import { PRIMARY_THEME_COLOR, commonColumn } from "../configs/constants"; -import { colorHeaders } from "../utils/uploadUtils"; - -const MicroplanCreatedScreen = memo(({ microplanData, ...props }) => { - const { t } = useTranslation(); - const history = useHistory(); - - const downloadMicroplan = async () => { - try { - if (!microplanData?.microplanPreview) return; - const data = _.cloneDeep(microplanData?.microplanPreview?.previewData); - const commonColumnIndex = data[0]?.findIndex((item) => item === commonColumn); - data[0] = data[0].map((item) => t(item)); - - for (const i in data) { - data[i] = data[i].map((item, index) => - item ? (typeof item === "number" ? item : index === commonColumnIndex ? item : t(item)) : t("NO_DATA") - ); - } - - const headers = data?.[0] || []; - const workbook = await convertJsonToXlsx({ [microplanData?.microplanDetails?.name]: data }, {}, true); - colorHeaders(workbook, headers, [], []); - const blob = await writeWorkbookToBuffer(workbook); - - if (!blob) { - return; - } - - const url = URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - - const fileNameParts = microplanData?.microplanDetails?.name; - if (!fileNameParts) { - return; - } - - link.download = fileNameParts; - link.click(); - URL.revokeObjectURL(url); - } catch (error) { - console.error(`Failed to download microplan: ${error.message}`, error); - } - }; - - const clickGoHome = () => { - history.push("/microplan-ui/employee"); - }; - - return ( -
-
-
- -
-

{t("MICROPLAN_GENERATED_SUCCESSFULLY_DESCRIPTIION")}

-
-
-
- - - {/* Back button */} -
- ); -}); - -export default MicroplanCreatedScreen; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js deleted file mode 100644 index fbc73bd6569..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js +++ /dev/null @@ -1,294 +0,0 @@ -import React, { Fragment, useState, useEffect, useCallback } from "react"; -import { - Card, - CardSubHeader, - CardSectionHeader, - StatusTable, - Row, - Loader, - LabelFieldPair, - CardLabel, - TextInput, - LoaderWithGap, -} from "@egovernments/digit-ui-react-components"; -import { useTranslation } from "react-i18next"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { InfoCard, Modal, Toast } from "@egovernments/digit-ui-components"; -import { CloseButton, ModalHeading } from "./CommonComponents"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; -import SearchPlanConfig from "../services/SearchPlanConfig"; - -const page = "microplanDetails"; - -const MicroplanDetails = ({ - MicroplanName = "default", - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - setToast, - ...props -}) => { - const { t } = useTranslation(); - const [microplan, setMicroplan] = useState(Digit.SessionStorage.get("microplanData")?.microplanDetails?.name); - const { state, dispatch } = useMyContext(); - const [modal, setModal] = useState("none"); - // const [toast, setToast] = useState(); - const [showNamingConventions, setShowNamingConventions] = useState(false); - const [loader, setLoader] = useState(false); - - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - select: (data) => { - const campaignCard = [ - { - label: t("CAMPAIGN_NAME"), - value: data?.campaignName ? data?.campaignName : t("ES_COMMON_NA"), - }, - { - label: t(`CAMPAIGN_TYPE`), - value: data?.projectType ? t(`CAMPAIGN_TYPE_${data?.projectType}`) : t("ES_COMMON_NA"), - }, - { - label: t(`CAMPAIGN_BENEFICIARY_TYPE`), - value: data?.additionalDetails?.beneficiaryType - ? t(`CAMPAIGN_BENEFICIARY_TYPE${data?.additionalDetails?.beneficiaryType}`) - : t("ES_COMMON_NA"), - }, - { - label: t("CAMPAIGN_DATE"), - value: data.startDate - ? data.endDate - ? `${Digit.DateUtils.ConvertEpochToDate(data.startDate)} - ${Digit.DateUtils.ConvertEpochToDate(data.endDate)}` - : Digit.DateUtils.ConvertEpochToDate(data.startDate) - : t("ES_COMMON_NA"), - }, - ]; - return campaignCard; - }, - } - ); - - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - // Save data to ssn of data change - useEffect(() => { - setMicroplanData((previous) => ({ - ...previous, - microplanDetails: { - name: microplan, - }, - })); - }, [microplan]); - - useEffect(() => { - if (checkDataCompletion !== "true" || !setCheckDataCompletion) return; - - updateData(true); - }, [checkDataCompletion]); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - // if (modal === "upload-guidelines") - setCheckDataCompletion("false"); - setModal("none"); - } - }; - const validateMicroplanName = async () => { - try { - setLoader("LOADING"); - const body = { - PlanConfigurationSearchCriteria: { - name: microplan, - tenantId: Digit.ULBService.getCurrentTenantId(), - }, - }; - const response = await SearchPlanConfig(body); - if (response?.PlanConfiguration?.length === 0) { - return true; - } - if (response?.PlanConfiguration?.length === 1) { - if (response?.PlanConfiguration[0].id === microplanData?.planConfigurationId) { - setLoader(); - return true; - } - } - setLoader(); - return false; - } catch (error) { - console.error("Error while checking microplan name duplication: ", error.message); - setLoader(); - return false; - } - }; - // check if data has changed or not - const updateData = useCallback( - async (check) => { - if (checkDataCompletion !== "true" || !setCheckDataCompletion) return; - if (!microplan || !validateName(microplan)) { - setCheckDataCompletion("false"); - setShowNamingConventions(true); - return setToast({ state: "error", message: t("ERROR_MICROPLAN_NAME_CRITERIA") }); - } - const valid = await validateMicroplanName(); - if (!valid) { - setToast({ state: "error", message: t("ERROR_DUPLICATE_MICROPLAN_NAME") }); - setCheckDataCompletion("false"); - return; - } - if (check) { - setMicroplanData((previous) => ({ - ...previous, - microplanDetails: { - name: microplan, - }, - })); - if (!["", null, undefined].includes(microplan)) { - setCheckDataCompletion("valid"); - } else { - setCheckDataCompletion("invalid"); - } - } else { - if (!["", null, undefined].includes(microplanData?.microplanDetails?.name)) { - setCheckDataCompletion("valid"); - } else { - setCheckDataCompletion("invalid"); - } - } - }, - [checkDataCompletion, microplan, microplanData, setCheckDataCompletion, setMicroplanData, validateMicroplanName] - ); - - // const cancelUpdateData = useCallback(() => { - // setCheckDataCompletion(false); - // setModal('none'); - // }, [setCheckDataCompletion, setModal]); - function validateName(name) { - const microplanNamingRegxString = state?.UIConfiguration?.find((item) => item.name === "microplanNamingRegx")?.microplanNamingRegx; - const namePattern = new RegExp(microplanNamingRegxString); - return namePattern.test(name); - } - const onChangeMicroplanName = (e) => { - setMicroplan(e.target.value); - }; - - if (isCampaignLoading) { - return ; - } - - return ( - <> - {loader && } - - - {t("CAMPAIGN_DETAILS")} - - - - {campaignData?.length > 0 && - campaignData?.map((row, idx) => { - return ( - - ); - })} - - - - {t("NAME_YOUR_MP")} -

{t("MP_FOOTER")}

- - - {`${t("NAME_OF_MP")} `}

*

-
-
- -
-
-
- - {state?.UIConfiguration?.find((item) => item.name === "microplanNamingConvention")?.microplanNamingConvention?.map((item, index) => ( -
-

- {t(index + 1)}. -

-

- {t(item)} -

-
- ))} -
, - ]} - /> - - ); -}; - -export default MicroplanDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js deleted file mode 100644 index 1be6619e7a7..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js +++ /dev/null @@ -1,478 +0,0 @@ -import { Header, Loader } from "@egovernments/digit-ui-components"; -import React, { useCallback, useEffect, useMemo, useState, Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { processHierarchyAndData } from "../utils/processHierarchyAndData"; -import { ModalHeading } from "./CommonComponents"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; -import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { - fetchMicroplanPreviewData, - filterObjects, - updateHyothesisAPICall, - filterMicroplanDataToShowWithHierarchySelection, -} from "../utils/microplanPreviewUtils"; -import { - HypothesisValues, - BoundarySelection, - DataPreview, - AppplyChangedHypothesisConfirmation, - Aggregates, -} from "./MicroplanPreviewHelperCompoenents"; - -const page = "microplanPreview"; - -const MicroplanPreview = ({ - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - navigationEvent, - setToast, - ...props -}) => { - const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig(); - const userInfo = Digit.SessionStorage.get("User")?.info; - const { id: campaignId = "" } = Digit.Hooks.useQueryParams(); - const { t } = useTranslation(); - const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); - const [data, setData] = useState([]); - const [dataToShow, setDataToShow] = useState([]); - const [joinByColumns, setJoinByColumns] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [resources, setResources] = useState([]); - const [formulaConfiguration, setFormulaConfiguration] = useState([]); - const [boundarySelections, setBoundarySelections] = useState({}); // state for hierarchy from the data available from uploaded data - const [boundaryData, setBoundaryData] = useState({}); // State for boundary data - // const [toast, setToast] = useState(); - const [modal, setModal] = useState("none"); - const [operatorsObject, setOperatorsObject] = useState([]); - - const [loaderActivation, setLoaderActivation] = useState(false); - - const [userEditedResources, setUserEditedResources] = useState({}); // state to maintain a record of the resources that the user has edited ( boundaryCode : {resource : value}) - const [microplanPreviewAggregates, setMicroplaPreviewAggregates] = useState(); - const { state, dispatch } = useMyContext(); - const [updateHypothesis, setUpdateHypothesis] = useState(false); - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - - // request body for boundary hierarchy api - const reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - hierarchyType: campaignData?.hierarchyType, - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return ( - data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ - ...item, - parentBoundaryType: item?.parentBoundaryType - ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` - : null, - boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, - })) || {} - ); - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchyRawData } = Digit.Hooks.useCustomAPIHook(reqCriteria); - const hierarchy = useMemo(() => { - return hierarchyRawData?.map((item) => item?.boundaryType); - }, [hierarchyRawData]); - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - // UseEffect to extract data on first render - useEffect(() => { - if (microplanData && (microplanData?.ruleEngine || microplanData?.hypothesis)) { - const hypothesisAssumptions = microplanData?.hypothesis || []; - const formulaConfiguration = microplanData?.ruleEngine?.filter((item) => Object.values(item).every((key) => key !== "")) || []; - if (hypothesisAssumptions.length !== 0 && hypothesisAssumptionsList.length === 0) { - setHypothesisAssumptionsList(hypothesisAssumptions); - } - if (formulaConfiguration.length !== 0) { - setFormulaConfiguration(formulaConfiguration); - } - } - if (microplanData?.microplanPreview?.userEditedResources) { - setUserEditedResources(microplanData?.microplanPreview?.userEditedResources); - } - }, []); - - // Fetch and assign MDMS data - useEffect(() => { - if (!state) return; - const UIConfiguration = state?.UIConfiguration; - const schemas = state?.Schemas; - let resourcelist = state?.Resources; - let microplanPreviewAggregatesList = state?.MicroplanPreviewAggregates; - microplanPreviewAggregatesList = microplanPreviewAggregatesList.find((item) => item.campaignType === campaignType)?.data; - if (schemas) setValidationSchemas(schemas); - resourcelist = resourcelist.find((item) => item.campaignType === campaignType)?.data; - if (resourcelist) setResources(resourcelist); - if (UIConfiguration) { - const joinWithColumns = UIConfiguration.find((item) => item.name === "microplanPreview")?.joinWithColumns; - setJoinByColumns(joinWithColumns); - } - let temp; - if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); - if (temp?.ruleConfigureOperators) { - setOperatorsObject(temp.ruleConfigureOperators); - } - if (microplanPreviewAggregatesList) setMicroplaPreviewAggregates(microplanPreviewAggregatesList); - }, []); - - // UseEffect for checking completeness of data before moveing to next section - useEffect(() => { - if (!dataToShow || checkDataCompletion !== "true" || !setCheckDataCompletion) return; - const check = filterObjects(hypothesisAssumptionsList, microplanData?.hypothesis); - if (check.length === 0) { - if (navigationEvent?.name === "next") return setModal("confirm-microplan-generation"); - return createMicroplan(false, false); - } - setModal("confirm-apply-changed-hypothesis"); - }, [checkDataCompletion]); - - // check if data has changed or not - const updateData = useCallback( - (doPerform) => { - // Update the microplan data with selected hierarchy and resources - // This function also handles setting the completion check based on the action to be performed - if (!setMicroplanData) return; - try { - let tempData = filterMicroplanDataToShowWithHierarchySelection(data, {}, hierarchy); - // Adding resources to the data we need to show - tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( - tempData, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - userEditedResources, - t - ); - setMicroplanData((previous) => ({ - ...previous, - microplanPreview: { - previewData: tempData, - userEditedResources, - }, - })); - if (doPerform) { - return setCheckDataCompletion("perform-action"); - } - setCheckDataCompletion("false"); - } catch (error) { - console.error("Failed to update data:", error); - } - }, - [ - resources, - boundarySelections, - hierarchy, - hypothesisAssumptionsList, - formulaConfiguration, - userEditedResources, - setMicroplanData, - setCheckDataCompletion, - ] - ); - - const cancelUpdateData = useCallback(() => { - setUpdateHypothesis(false); - if (navigationEvent?.name === "next") setModal("confirm-microplan-generation"); - else createMicroplan(false, false); - }, [setCheckDataCompletion, setModal]); - - useEffect(() => { - if (boundarySelections && Object.values(boundarySelections).every((item) => item.length === 0) && hierarchy) { - const tempBoundarySelection = {}; - for (const item of hierarchy) { - tempBoundarySelection[item] = []; - } - setBoundarySelections(tempBoundarySelection); - } - }, [hierarchy]); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - setCheckDataCompletion("false"); - setModal("none"); - } - }; - - const cancleNavigation = () => { - if (navigationEvent?.name !== "next") setCheckDataCompletion("false"); - setModal("none"); - }; - - const createMicroplan = useCallback( - (doCreation, updateHypothesis) => { - if (!hypothesisAssumptionsList || !setMicroplanData) return; - const updateDataWrapper = () => { - if (doCreation || navigationEvent?.name !== "next") { - return updateData(true); - } - updateData(false); - }; - const setCheckDataCompletionWrapper = (value) => { - if (!doCreation) { - return setCheckDataCompletion("false"); - } - setCheckDataCompletion(value); - }; - const microData = updateHypothesis ? updateMicroplanData(hypothesisAssumptionsList) : microplanData; - setLoaderActivation(true); - updateHyothesisAPICall( - microData, - setMicroplanData, - operatorsObject, - microData?.microplanDetails?.name, - campaignId, - UpdateMutate, - setToast, - updateDataWrapper, - setLoaderActivation, - doCreation && navigationEvent?.name === "next" ? "GENERATED" : "DRAFT", - cancleNavigation, - state, - campaignType, - navigationEvent, - setCheckDataCompletionWrapper, - t - ); - - setUpdateHypothesis(false); - setModal("none"); - }, - [ - hypothesisAssumptionsList, - setMicroplanData, - operatorsObject, - campaignId, - UpdateMutate, - setToast, - updateData, - setLoaderActivation, - navigationEvent, - t, - ] - ); - - const updateMicroplanData = useCallback( - (hypothesisAssumptionsList) => { - let microData = {}; - setMicroplanData((previous) => { - microData = { ...previous, hypothesis: hypothesisAssumptionsList }; - return microData; - }); - return microData; - }, - [setMicroplanData] - ); - - // Set microplan preview data - useEffect(() => { - if (data?.length !== 0 || !hierarchyRawData || !hierarchy || validationSchemas?.length === 0) return; - - const combinedData = fetchMicroplanPreviewData(campaignType, microplanData, validationSchemas, hierarchy); - // process and form hierarchy - if (combinedData && hierarchy) { - const { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchyRawData, [combinedData]); - setBoundaryData({ Microplan: { hierarchyLists, hierarchicalData } }); - } - if (combinedData) { - setData(combinedData); - setDataToShow(combinedData); - } - }, [hierarchy, hierarchyRawData, microplanData]); - - useEffect(() => { - if (!boundarySelections && !resources) return; - let tempData = filterMicroplanDataToShowWithHierarchySelection(data, boundarySelections, hierarchy); - // Adding resources to the data we need to show - tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( - tempData, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - userEditedResources, - t - ); - setDataToShow(tempData); - setMicroplanData((previous) => ({ ...previous, microplanPreview: { ...previous.microplanPreview, previewData: tempData, userEditedResources } })); - }, [boundarySelections, resources, hypothesisAssumptionsList, userEditedResources]); - - if (isCampaignLoading || ishierarchyLoading) { - return ( -
- -
- ); - } - - return ( - <> -
-
-

{t(campaignData?.campaignName)}

-
{t(microplanData?.microplanDetails?.name)}
-

{t("MICROPLAN_PREVIEW_CREATE_BY", { username: userInfo?.name })}

-
-
-
- -
-
- -
-
-

{t("MICROPLAN_PREVIEW_HYPOTHESIS_HEADING")}

-

{t("MICROPLAN_PREVIEW_HYPOTHESIS_INSTRUCTIONS")}

- -
-
- {dataToShow?.length != 0 ? ( - - ) : ( -
{t("NO_DATA_AVAILABLE")}
- )} -
-
- {modal === "confirm-apply-changed-hypothesis" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={() => { - setUpdateHypothesis(true); - if (navigationEvent?.name === "next") setModal("confirm-microplan-generation"); - else createMicroplan(false, true); - }} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={cancelUpdateData} - formId="modal-action" - > - - - )} - {modal === "confirm-microplan-generation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={() => createMicroplan(true, updateHypothesis)} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={() => createMicroplan(false, updateHypothesis)} - formId="modal-action" - > -
-

{t("INSTRUCTIONS_MICROPLAN_GENERATION_CONFIRMATION")}

-
-
- )} -
- {loaderActivation && } - - ); -}; - -export default MicroplanPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js deleted file mode 100644 index e92335d6581..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js +++ /dev/null @@ -1,434 +0,0 @@ -import { CardLabel, Loader, MultiSelectDropdown, TextInput } from "@egovernments/digit-ui-components"; -import React, { memo, useCallback, useEffect, useMemo, useState, Fragment, useRef } from "react"; -import { fetchDropdownValues } from "../utils/processHierarchyAndData"; -import { CloseButton, ModalHeading } from "./CommonComponents"; -import { PRIMARY_THEME_COLOR, commonColumn } from "../configs/constants"; -import { Button, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import { useNumberFormatter } from "../hooks/useNumberFormatter"; -import { calculateAggregateValue, filterObjects, useHypothesis } from "../utils/microplanPreviewUtils"; - -export const HypothesisValues = memo(({ boundarySelections, hypothesisAssumptionsList, setHypothesisAssumptionsList, setToast, setModal, t }) => { - const [tempHypothesisList, setTempHypothesisList] = useState(hypothesisAssumptionsList || []); - const { valueChangeHandler } = useHypothesis(tempHypothesisList, hypothesisAssumptionsList); - const contentRef = useRef(null); - const [isScrollable, setIsScrollable] = useState(false); - - const applyNewHypothesis = () => { - if (tempHypothesisList.some((item) => item.active && (Number.isNaN(parseFloat(item.value)) || parseFloat(item.value) === 0))) { - setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") }); - return; - } - if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) - return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); - setHypothesisAssumptionsList(tempHypothesisList); - }; - const checkScrollbar = () => { - if (contentRef.current) { - setIsScrollable(contentRef.current.scrollHeight > contentRef.current.clientHeight); - } - }; - - useEffect(() => { - // Initial check - checkScrollbar(); - - // Check on resize - window.addEventListener("resize", checkScrollbar); - - // Cleanup event listeners on component unmount - return () => { - window.removeEventListener("resize", checkScrollbar); - }; - }, []); - - useEffect(() => { - const content = contentRef.current; - content.addEventListener("scroll", checkScrollbar); - - return () => { - content.removeEventListener("scroll", checkScrollbar); - }; - }, [contentRef]); - - return ( -
-
- {tempHypothesisList - .filter((item) => item?.active) - ?.filter((item) => item.key !== "") - .map((item, index) => ( -
-

{t(item?.key)}

-
- {/* Dropdown for boundaries */} - - valueChangeHandler({ item, newValue: value?.target?.value }, setTempHypothesisList, boundarySelections, setToast, t) - } - disable={false} - /> -
-
- ))} -
-
-
-
- ); -}); - -export const BoundarySelection = memo(({ boundarySelections, setBoundarySelections, boundaryData, hierarchy, t }) => { - const [processedHierarchy, setProcessedHierarchy] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [changedBoundaryType, setChangedBoundaryType] = useState(""); - - // Filtering out dropdown values - useEffect(() => { - if (!boundaryData || !hierarchy) return; - - const processedHierarchyTemp = fetchDropdownValues( - boundaryData, - processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, - boundarySelections, - changedBoundaryType - ); - setProcessedHierarchy(processedHierarchyTemp); - setIsLoading(false); - }, [boundaryData, hierarchy, boundarySelections]); - - return ( -
- {isLoading && } - {processedHierarchy?.map((item, index) => ( -
- {t(item?.boundaryType)} - {item?.parentBoundaryType === null ? ( - 5 ? { height: "13.75rem" } : {}} - type={"multiselectdropdown"} - t={t} - options={item?.dropDownOptions || []} - optionsKey="name" - addSelectAllCheck={true} - onSelect={(e) => { - setChangedBoundaryType(item?.boundaryType); - Digit.Utils.microplan.handleSelection( - e, - item?.boundaryType, - boundarySelections, - hierarchy, - setBoundarySelections, - boundaryData, - setIsLoading - ); - }} - /> - ) : ( - 5 ? { height: "13.75rem" } : {}} - type={"multiselectdropdown"} - t={t} - options={Digit.Utils.microplan.processDropdownForNestedMultiSelect(item?.dropDownOptions) || []} - optionsKey="name" - addSelectAllCheck={true} - onSelect={(e) => { - setChangedBoundaryType(item?.boundaryType); - Digit.Utils.microplan.handleSelection( - e, - item?.boundaryType, - boundarySelections, - hierarchy, - setBoundarySelections, - boundaryData, - setIsLoading - ); - }} - variant="nestedmultiselect" - /> - )} -
- ))} -
- ); -}); - -export const DataPreview = memo( - ({ previewData, isCampaignLoading, ishierarchyLoading, resources, userEditedResources, setUserEditedResources, modal, setModal, data, t }) => { - if (!previewData) return; - const [tempResourceChanges, setTempResourceChanges] = useState(userEditedResources); - const [selectedRow, setSelectedRow] = useState(); - const conmmonColumnIndex = useMemo(() => { - return previewData?.[0]?.indexOf(commonColumn); - }, [previewData]); - if (isCampaignLoading || ishierarchyLoading) { - return ( -
- -
- ); - } - - const rowClick = useCallback((rowIndex) => { - setSelectedRow(rowIndex); - setModal("change-preview-data"); - }, []); - - const finaliseRowDataChange = () => { - setUserEditedResources(tempResourceChanges); - setModal("none"); - setSelectedRow(undefined); - }; - - const modalCloseHandler = () => { - setModal("none"); - setSelectedRow(undefined); - }; - - return ( -
-
- - - - {previewData[0].map((header, columnIndex) => ( - - ))} - - - - {previewData.slice(1).map((rowData, rowIndex) => { - const rowDataList = Object.values(previewData[0]).map((header, cellIndex) => ( - - )); - return ( - { - rowClick(rowIndex + 1); - }} - // style={{...(userEditedResources?.[rowData?.[conmmonColumnIndex]] && Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !==0 - // ? { borderL: "1px solid rgba(244, 119, 56, 0.12)" } - // : {}),}} - > - {rowDataList} - - ); - })} - -
- {t(header)} -
- {cellIndex === 0 && - userEditedResources?.[rowData?.[conmmonColumnIndex]] && - Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !== 0 &&
} - - {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : t("NO_DATA")} -
-
- {modal === "change-preview-data" && ( -
- } - headerBarEnd={} - actionCancelLabel={t("CANCLE")} - actionCancelOnSubmit={modalCloseHandler} - actionSaveLabel={t("SAVE_CHANGES")} - actionSaveOnSubmit={finaliseRowDataChange} - formId="modal-action" - > - - -
- )} -
- ); - } -); - -export const AppplyChangedHypothesisConfirmation = ({ newhypothesisList, hypothesisList, t }) => { - const data = filterObjects(newhypothesisList, hypothesisList); - return ( -
-
-

{t("INSTRUCTION_PROCEED_WITH_NEW_HYPOTHESIS")}

-
- - {t("MICROPLAN_PREVIEW_HYPOTHESIS")} - -
- - - - - - - - - - {data?.map((row, index) => ( - - - - - - ))} - -
{t("KEYS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
{t(row?.key)}{t(row?.oldValue)}{t(row?.value)}
-
-
- ); -}; - -export const EditResourceData = ({ previewData, selectedRow, resources, tempResourceChanges, setTempResourceChanges, data, t }) => { - const conmmonColumnData = useMemo(() => { - const index = previewData?.[0]?.indexOf(commonColumn); - if (index === -1) return; - return previewData?.[selectedRow]?.[index]; - }, [previewData]); - - const valueChangeHandler = (item, value) => { - if (!conmmonColumnData) return; - if (isNaN(value) || (!isFinite(value) && value !== "")) return; - let changedDataAgainstBoundaryCode = tempResourceChanges?.[conmmonColumnData] || {}; - changedDataAgainstBoundaryCode[item] = value === "" ? undefined : parseFloat(value); - setTempResourceChanges((previous) => ({ ...previous, [conmmonColumnData]: changedDataAgainstBoundaryCode })); - }; - - return ( -
- - - - - - - - - - {data[0].map((item) => { - let index = data?.[0]?.indexOf(item); - if (index === -1) return; - const currentData = data?.[selectedRow]?.[index]; - return ( - - - - - - ); - })} - {resources.map((item) => { - let index = previewData?.[0]?.indexOf(item); - if (index === -1) return; - const currentData = previewData?.[selectedRow]?.[index]; - - return ( - - - - - - ); - })} - -
{t("COLUMNS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
-

{t(item)}

-
-

{currentData || t("NO_DATA")}

-
- -
-

{t(item)}

-
-

{currentData || t("NO_DATA")}

-
- valueChangeHandler(item, value.target.value)} - /> -
-
- ); -}; - -export const Aggregates = memo(({ microplanPreviewAggregates, dataToShow, NumberFormatMappingForTranslation, t }) => { - const { formatNumber } = useNumberFormatter(NumberFormatMappingForTranslation?.reduce((acc, obj) => Object.assign(acc, obj), {})); - - if (!microplanPreviewAggregates) return null; - return ( -
- {microplanPreviewAggregates.map((item, index) => { - const aggregate = calculateAggregateValue(item, dataToShow); - return ( -
-

{isNaN(parseInt(aggregate)) ? 0 : formatNumber(parseInt(aggregate))}

-

{typeof item === "object" && item.name ? t(item.name) : t(item)}

-
- ); - })} -
- ); -}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js deleted file mode 100644 index 9a1dd8f5500..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js +++ /dev/null @@ -1,34 +0,0 @@ -import { EmployeeModuleCard, WorksMgmtIcon } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useTranslation } from "react-i18next"; - -const ROLES = { - MICROPLAN: ["MICROPLAN_ADMIN"], -}; - -const MicroplanningCard = () => { - const { t } = useTranslation(); - const tenantId = Digit.ULBService.getCurrentTenantId(); - - const generateLink = (labelKey, pathSuffix) => { - return { - label: t(labelKey), - link: `/${window?.contextPath}/employee/microplanning/${pathSuffix}`, - roles: ROLES.MICROPLAN, - }; - }; - - let links = [generateLink("CREATE_NEW_MICROPLAN", "select-campaign"), generateLink("OPEN_SAVED_MICROPLANS", "saved-microplans")]; - - links = links.filter((link) => (link?.roles && link?.roles?.length > 0 ? Digit.Utils.didEmployeeHasAtleastOneRole(link?.roles) : true)); - - const propsForModuleCard = { - Icon: , - moduleName: t("Microplanning"), - kpis: [], - links: links, - }; - return ; -}; - -export default MicroplanningCard; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js deleted file mode 100644 index 2a35e9c0995..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js +++ /dev/null @@ -1,29 +0,0 @@ -import { Help, Tutorial, useTourState } from "@egovernments/digit-ui-react-components"; -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { useLocation } from "react-router-dom"; -import { useMyContext } from "../utils/context"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; - -const MicroplanningHeader = () => { - const { tourState, setTourState } = useTourState(); - const { state } = useMyContext(); - const { t } = useTranslation(); - //using location.pathname we can update the stepIndex accordingly when help is clicked from any other screen(other than home screen) - const { pathname } = useLocation(); - - const startTour = () => { - if (state?.tourStateData) setTourState(state.tourStateData); - }; - - return ( - <> - -
- -
- - ); -}; - -export default MicroplanningHeader; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js deleted file mode 100644 index 0792ee2e52d..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js +++ /dev/null @@ -1,158 +0,0 @@ -import React, { useEffect } from "react"; -import { PopUp, HeaderBar, Toast, CloseButton, ButtonSelector } from "@egovernments/digit-ui-react-components"; -import { Close } from "@egovernments/digit-ui-svg-components"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; - -const Modal = ({ - headerBarMain, - headerBarEnd, - popupStyles, - children = {}, - actionCancelLabel, - actionCancelOnSubmit, - actionSaveLabel, - actionSaveOnSubmit, - error, - setError, - formId, - isDisabled, - hideSubmit, - style = {}, - footerLeftButtonstyle = {}, - footerRightButtonstyle = {}, - footerLeftButtonBody, - footerRightButtonBody, - popupModuleMianStyles, - headerBarMainStyle, - isOBPSFlow = false, - popupModuleActionBarStyles = {}, -}) => { - /** - * TODO: It needs to be done from the desgin changes - */ - const mobileView = Digit.Utils.browser.isMobile(); - useEffect(() => { - document.body.style.overflowY = "hidden"; - return () => { - document.body.style.overflowY = "auto"; - }; - }, []); - - return ( - -
- -
- {children} -
- {actionCancelLabel || footerLeftButtonBody ? ( - 0 ? style : footerLeftButtonstyle} - /> - ) : null} - {!hideSubmit ? ( - 0 ? style : footerRightButtonstyle} - /> - ) : null} -
-
-
- {error && setError(null)} type="error" />} -
- ); -}; - -const moduleActionBarStyle = (isOBPSFlow, popupModuleActionBarStyles) => { - return isOBPSFlow - ? !mobileView - ? { marginRight: "18px" } - : { position: "absolute", bottom: "5%", right: "10%", left: window.location.href.includes("employee") ? "0%" : "7%" } - : popupModuleActionBarStyles; -}; - -// Wrapper for modal -export const ModalWrapper = ({ - closeModal, - LeftButtonHandler, - RightButtonHandler, - footerLeftButtonBody, - footerRightButtonBody, - header, - bodyText, - body, - popupStyles, - headerBarMainStyle, - popupModuleActionBarStyles, - hideSubmit, - closeButton = false, - actionCancelLabel, -}) => { - return ( - - {" "} - - - ) : ( - "" - ) - } - actionCancelOnSubmit={LeftButtonHandler} - actionSaveOnSubmit={RightButtonHandler} - formId="microplanning" - popupStyles={{ width: "33.375rem", borderRadius: "0.25rem", ...(popupStyles ? popupStyles : {}) }} - headerBarMainStyle={{ margin: 0, width: "33.375rem", overflow: "hidden", ...(headerBarMainStyle ? headerBarMainStyle : {}) }} - popupModuleMianStyles={{ margin: 0, padding: 0 }} - popupModuleActionBarStyles={popupModuleActionBarStyles ? popupModuleActionBarStyles : { justifyContent: "space-between", padding: "1rem" }} - style={{}} - hideSubmit={hideSubmit ? hideSubmit : false} - footerLeftButtonstyle={{ - padding: 0, - alignSelf: "flex-start", - height: "fit-content", - textStyles: { fontWeight: "600" }, - backgroundColor: "rgba(255, 255, 255, 1)", - color: PRIMARY_THEME_COLOR, - minWidth: "15.063rem", - border: `0.063rem solid ${PRIMARY_THEME_COLOR}`, - }} - footerRightButtonstyle={{ - padding: 0, - alignSelf: "flex-end", - height: "fit-content", - textStyles: { fontWeight: "500" }, - backgroundColor: PRIMARY_THEME_COLOR, - color: "rgba(255, 255, 255, 1)", - minWidth: "15.063rem", - boxShadow: "0px -2px 0px 0px rgba(11, 12, 12, 1) inset", - }} - footerLeftButtonBody={footerLeftButtonBody} - footerRightButtonBody={footerRightButtonBody} - actionCancelLabel={actionCancelLabel} - > - {bodyText && ( -
-

{bodyText}

-
- )} - {body ? body : ""} -
- ); -}; - -export default Modal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js deleted file mode 100644 index 06d04ef2296..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js +++ /dev/null @@ -1,272 +0,0 @@ -import { ActionBar, Stepper, Toast } from "@egovernments/digit-ui-components"; -import PropTypes from "prop-types"; -import React, { useState, useEffect, useCallback } from "react"; -import { useTranslation } from "react-i18next"; -import { Button } from "@egovernments/digit-ui-react-components"; -import { ArrowBack, ArrowForward } from "@egovernments/digit-ui-svg-components"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; -import { memo } from "react"; - -/** - * - * @param { config: Object, checkDataCompleteness: boolean, components: Object, childProps: Object, stepNavigationActive: boolean, nextEventAddon: function, setCurrentPageExternally: function, completeNavigation } props - * @returns - * - */ -// Main component for creating a microplan -const Navigator = memo((props) => { - // States - const [currentPage, setCurrentPage] = useState(); - // const [toast, setToast] = useState(); - const [navigationEvent, setNavigationEvent] = useState(); - const [activeSteps, setActiveSteps] = useState(Digit.SessionStorage.get("microplanHelperData")?.activeSteps || -1); - /** - * checkDataCompletion - * "true": check for data completeness - * "false": do nothing - * "valid": data is present - * "invalid": whole or a part of the data is missing - * "perform-action": move to the respective step ( had to add this as mutate addons need some buffer time) - */ - const [checkDataCompletion, setCheckDataCompletion] = useState("false"); - - const { t } = useTranslation(); - - // Effect to set initial current page when timeline options change - useEffect(() => { - if (!props.config || props.config.length === 0) return; - let response; - if (props.setCurrentPageExternally) { - response = props.setCurrentPageExternally({ setCurrentPage, method: "set" }); - } - if (!response) setCurrentPage(props.config[0]); - }, [props.config]); - - // Might need it later - // Effect to handle data completion validation and show toast - useEffect(() => { - if (checkDataCompletion === "invalid") { - if (navigationEvent && navigationEvent.name === "next") { - props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") }); - } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step !== undefined) { - if (navigationEvent.step > currentPage.id) - props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") }); - else onStepClick(navigationEvent.step); - } else if (navigationEvent && navigationEvent.name === "previousStep") previousStep(); - setCheckDataCompletion("false"); - } - }, [checkDataCompletion]); - - // Effect to handle navigation events and transition between steps - useEffect(() => { - // if (checkDataCompletion !== "valid" || navigationEvent === undefined) return; - if ( - checkDataCompletion === "valid" && - ((navigationEvent.step && currentPage.id + 1 === navigationEvent.step) || currentPage.id > navigationEvent.step || !navigationEvent.step) - ) { - if (typeof props.nextEventAddon === "function") { - if (LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) - props.nextEventAddon(currentPage, checkDataCompletion, setCheckDataCompletion); - else props.nextEventAddon(currentPage, true, setCheckDataCompletion); - } else { - setCheckDataCompletion("perform-action"); - } - } - }, [navigationEvent, checkDataCompletion, props.nextEventAddon]); - - useEffect(() => { - handleNavigationEvent( - checkDataCompletion, - navigationEvent, - currentPage, - setCheckDataCompletion, - setNavigationEvent, - onStepClick, - nextStep, - previousStep, - props - ); - }, [checkDataCompletion, navigationEvent]); - - // Function to navigate to the next step - const nextStep = useCallback(() => { - if (!currentPage) return; - changeCurrentPage(props.config[currentPage?.id + 1]); - if (currentPage?.id + 1 > props.config.length - 1) return; - setCurrentPage((previous) => props.config[previous?.id + 1]); - }, [currentPage]); - - // Function to navigate to the previous step - const previousStep = useCallback(() => { - changeCurrentPage(props.config[currentPage?.id - 1]); - setCurrentPage((previous) => props.config[previous?.id - 1]); - }, [currentPage]); - - // Function to handle step click and navigate to the selected step - const onStepClick = useCallback((index) => { - const newCurrentPage = props.config.find((item) => item.id === index); - changeCurrentPage(newCurrentPage); - setCurrentPage(newCurrentPage); - }); - - // Function to handle next button click - const previousbuttonClickHandler = useCallback(() => { - if ( - (props.checkDataCompleteness && - props?.config[currentPage?.id]?.checkForCompleteness && - LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) || - currentPage?.id === props.config[props.config.length - 1].id - ) { - setNavigationEvent({ name: "previousStep" }); - setCheckDataCompletion("true"); - } else previousStep(); - }, [props.checkDataCompleteness, previousStep, setNavigationEvent]); - - // Function to handle next button click - const nextbuttonClickHandler = useCallback(() => { - if ( - props.checkDataCompleteness && - props?.config[currentPage?.id]?.checkForCompleteness && - LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null - ) { - setCheckDataCompletion("true"); - setNavigationEvent({ name: "next" }); - } else nextStep(); - }, [props.checkDataCompleteness, nextStep, setNavigationEvent]); - - // Function to handle step click - const stepClickHandler = useCallback( - (index) => { - if (index === currentPage?.id) return; - if (!props.stepNavigationActive) return; - if ( - (props.checkDataCompleteness && - props?.config[currentPage?.id]?.checkForCompleteness && - LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) || - currentPage?.id === props.config[props.config.length - 1].id - ) { - setCheckDataCompletion("true"); - setNavigationEvent({ name: "step", step: index }); - } else { - onStepClick(index); - } - }, - [props.checkDataCompleteness, props.stepNavigationActive, onStepClick] - ); - - // Function to set current page - const changeCurrentPage = (newPage) => { - if (props.setCurrentPageExternally) { - props.setCurrentPageExternally({ currentPage: newPage, method: "save" }); - } - }; - - const completeNavigation = () => { - setNavigationEvent({ name: "next" }); - setCheckDataCompletion("true"); - }; - - // changing active state - useEffect(() => { - if (currentPage?.id > activeSteps) { - setActiveSteps(currentPage?.id); - Digit.SessionStorage.set("microplanHelperData", { ...(Digit.SessionStorage.get("microplanHelperData") || {}), activeSteps: currentPage?.id }); - } - }, [currentPage]); - - return ( -
- {/* Stepper component */} - t(item.name))} - direction="horizontal" - activeSteps={activeSteps >= 0 ? activeSteps + 1 : null} - onStepClick={stepClickHandler} - /> - - {/* Load custom component based on current page */} - {props?.components[currentPage?.component] ? ( - LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null ? ( - - ) : ( -
{t("COMMON_DATA_NOT_PRESENT")}
- ) - ) : ( - "" - )} - - {/* Action bar */} - - {/* Back button */} - {currentPage?.id > 0 && ( - - -
- ); -}); - -// Component to load custom component based on current page -const LoadCustomComponent = (props) => { - if (props && !props.component) return null; - const secondaryProps = props.secondaryProps; - return ; -}; -LoadCustomComponent.propTypes = { - component: PropTypes.elementType.isRequired, - secondaryProps: PropTypes.object, -}; - -const handleNavigationEvent = ( - checkDataCompletion, - navigationEvent, - currentPage, - setCheckDataCompletion, - setNavigationEvent, - onStepClick, - nextStep, - previousStep, - props -) => { - if (checkDataCompletion === "perform-action") { - if (navigationEvent && navigationEvent.name === "next") { - if (currentPage?.id === props.config.length - 1 && typeof props?.completeNavigation === "function") { - return props?.completeNavigation(); - } - nextStep(); - } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step !== undefined) onStepClick(navigationEvent.step); - else if (navigationEvent && navigationEvent.name === "previousStep") previousStep(); - setCheckDataCompletion("false"); - setNavigationEvent(undefined); - } -}; - -export default Navigator; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js deleted file mode 100644 index 7ece3cce04d..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js +++ /dev/null @@ -1,876 +0,0 @@ -import React, { useState, useEffect, useCallback, Fragment, useRef } from "react"; -import { useTranslation } from "react-i18next"; -import { Info, Trash } from "@egovernments/digit-ui-svg-components"; -import { ModalHeading } from "./CommonComponents"; -import { Button, Modal } from "@egovernments/digit-ui-react-components"; -import { Dropdown, InfoCard, Toast } from "@egovernments/digit-ui-components"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { v4 as uuidv4 } from "uuid"; -import { PlusWithSurroundingCircle } from "../icons/Svg"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; - -const page = "ruleEngine"; - -const RuleEngine = ({ - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - setToast, -}) => { - const { t } = useTranslation(); - - // States - const [editable, setEditable] = useState(true); - const [modal, setModalState] = useState("none"); - const [rules, setRules] = useState([]); - const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); - const [itemForDeletion, setItemForDeletion] = useState(); - const [exampleOption, setExampleOption] = useState(""); - const [inputs, setInputs] = useState([]); - const [outputs, setOutputs] = useState([]); - const [operators, setOperators] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [autofillData, setAutoFillData] = useState([]); - const { state, dispatch } = useMyContext(); - const [originalRuleOutputCount, setOriginalRuleOutputCount] = useState(0); - // const [toast, setToast] = useState(); - const [pureInputList, setPureInputList] = useState([]); - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - const setModal = (modalString) => { - const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); - elements.forEach((element) => { - element.classList.toggle("popup-wrap-rest-unfocus-active"); - }); - setModalState(modalString); - }; - - // UseEffect to extract data on first render - useEffect(() => { - if (pages) { - const previouspage = pages[currentPage?.id - 1]; - if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); - else setEditable(true); - } - }, []); - - // UseEffect for checking completeness of data before moveing to next section - useEffect(() => { - if (!rules || checkDataCompletion !== "true" || !setCheckDataCompletion) return; - // uncomment to activate data change save check - // if (!microplanData?.ruleEngine || !_.isEqual(rules, microplanData.ruleEngine)) setModal("data-change-check"); - // else - updateData(true); - }, [checkDataCompletion]); - - // UseEffect to store current data - useEffect(() => { - if (!rules || !setMicroplanData) return; - setMicroplanData((previous) => ({ ...previous, ruleEngine: rules })); - }, [rules]); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - // if (modal === "upload-guidelines") - setCheckDataCompletion("false"); - setModal("none"); - } - }; - - // check if data has changed or not - const updateData = useCallback( - (check) => { - if (!rules || !setMicroplanData) return; - if (check) { - setMicroplanData((previous) => ({ ...previous, ruleEngine: rules })); - const activeRules = rules.filter((item) => item.active); - const isValid = activeRules.every((item) => Object.values(item).every((data) => data !== "")) && activeRules.length !== 0; - if (isValid) setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } else { - let isValid = microplanData?.ruleEngine?.every((item) => Object.values(item).every((data) => data !== "")); - isValid = isValid && rules.length !== 0; - if (isValid) setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } - }, - [rules, setMicroplanData, microplanData, setCheckDataCompletion] - ); - - const cancelUpdateData = useCallback(() => { - setCheckDataCompletion(false); - setModal("none"); - }, [setCheckDataCompletion, setModal]); - - // useEffect to initialise the data from MDMS - useEffect(() => { - if (!state) return; - const schemas = state?.Schemas; - const hypothesisAssumptions = []; - microplanData?.hypothesis?.filter((item) => item.active).forEach((item) => (item.key !== "" ? hypothesisAssumptions.push(item.key) : null)); - const ruleConfigureOutput = state?.RuleConfigureOutput; - const UIConfiguration = state?.UIConfiguration; - const ruleConfigureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas) || []; - let AutoFilledRuleConfigurationsList = state?.AutoFilledRuleConfigurations; - AutoFilledRuleConfigurationsList = AutoFilledRuleConfigurationsList.find((item) => item.campaignType === campaignType)?.data; - microplanData?.ruleEngine?.forEach((item) => { - if (Object.values(item).every((e) => e !== "")) ruleConfigureInputs.push(item?.output); - }); - if (schemas) setValidationSchemas(schemas); - - let temp; - setHypothesisAssumptionsList(hypothesisAssumptions); - let outputs; - if (ruleConfigureOutput) temp = ruleConfigureOutput?.find((item) => item.campaignType === campaignType); - if (temp?.data) { - let data = temp.data; - setOriginalRuleOutputCount(data.length); - microplanData?.ruleEngine?.forEach((item) => { - if (item.active) { - const filteredData = data.filter((e) => e !== item?.output); - data = filteredData; - } - }); - outputs = data; - setOutputs(data); - } - - if (ruleConfigureInputs) setInputs(ruleConfigureInputs); - let operator; - if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); - if (temp?.ruleConfigureOperators) { - temp = temp.ruleConfigureOperators.map((item) => item.name); - operator = temp; - setOperators(temp); - } - // if (AutoFilledRuleConfigurationsList) setAutoFillData(AutoFilledRuleConfigurationsList); - // Pure inputs - output not there - const pureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas); - setPureInputList(pureInputs); - - const ssnRuleOutputs = microplanData?.ruleEngine?.reduce((acc, item) => { - if (item?.active && item?.output) acc.push(item?.output); - return acc; - }, []); - const tempOutput = [...outputs, ...(ssnRuleOutputs ? ssnRuleOutputs : [])]; - setExampleOption({ - output: tempOutput.length ? tempOutput[0] : "", - input: pureInputs.length ? pureInputs[0] : "", - operator: operator.length ? operator[0] : "", - assumptionValue: hypothesisAssumptions.length ? hypothesisAssumptions[0] : "", - }); - - let filteredRules = []; - let response; - if (microplanData?.ruleEngine && microplanData?.hypothesis) { - const hypothesisAssumptions = microplanData?.hypothesis?.filter((item) => item.active && item.key !== "").map((item) => item.key) || []; - if (hypothesisAssumptions.length !== 0) { - setHypothesisAssumptionsList(hypothesisAssumptions); - response = filterRulesAsPerConstrains( - microplanData.ruleEngine, - [], - hypothesisAssumptions, - tempOutput, - operator, - pureInputs, - setInputs, - setOutputs, - false - ); - filteredRules = response?.rules; - - // setRuleEngineDataFromSsn(microplanData.ruleEngine, hypothesisAssumptions, setRules); - } - } - if (response?.rulesDeleted) - setToast({ - state: "warning", - message: t("WARNING_RULES_DELETED_DUE_TO_PRIOR_SECTION_DATA_CHANGES"), - }); - if (!AutoFilledRuleConfigurationsList || !outputs || !hypothesisAssumptions || !schemas) return; - - response = filterRulesAsPerConstrains( - AutoFilledRuleConfigurationsList, - filteredRules, - hypothesisAssumptions, - outputs, - operator, - pureInputs, - setInputs, - setOutputs, - true - ); - - if (response?.rules) setRules(response?.rules); - }, []); - - const closeModal = useCallback(() => { - setModal("none"); - }, [setModal]); - - // Function to Delete an assumption - const deleteAssumptionHandlerCallback = useCallback(() => { - deleteAssumptionHandler(itemForDeletion, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList); - closeModal(); - }, [itemForDeletion, deleteAssumptionHandler, setItemForDeletion, setRules, setOutputs, setInputs, closeModal, pureInputList]); - - const sectionClass = `jk-header-btn-wrapper rule-engine-section ${editable ? "" : "non-editable-component"} popup-wrap-rest-unfocus`; - return ( - <> -
-
-
- {/* NonInterractable Section */} - - {/* Interractable Section that includes the example as well as the rules */} - -
- -
-
- {/* delete conformation */} -
- {modal === "delete-conformation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={deleteAssumptionHandlerCallback} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={closeModal} - > -
-

{t("RULE_ENGINE_INSTRUCTIONS_DELETE_ENTRY_CONFIRMATION")}

-
-
- )} -
- - ); -}; - -// Function to add a new assumption -const addRulesHandler = (setRules) => { - const uuid = uuidv4(); - setRules((previous) => [ - ...previous, - { - id: uuid, - // previous.length ? previous[previous.length - 1].id + 1 : 0, - output: "", - input: "", - operator: "", - assumptionValue: "", - active: true, - }, - ]); -}; - -// Defination for NonInterractable Section -const NonInterractableSection = React.memo(({ t }) => { - return ( -
-

{t("HEADING_RULE_ENGINE")}

-

{t("INSTRUCTION_RULE_ENGINE")}

-
- ); -}); - -// Defination for NonInterractable Section -const InterractableSection = React.memo( - ({ - rules, - setRules, - hypothesisAssumptionsList, - setHypothesisAssumptionsList, - setModal, - setItemForDeletion, - exampleOption, - inputs, - outputs, - operators, - setInputs, - setOutputs, - setOperators, - pureInputList, - t, - }) => { - // References to the items in the list - const itemRefs = useRef([]); - // State to keep track of the currently expanded item index - const [expandedIndex, setExpandedIndex] = useState(null); - // Reference to the scroll container - const scrollContainerRef = useRef(null); - // State to track the render cycle count - const [renderCycle, setRenderCycle] = useState(0); - - // Effect to reset the render cycle count whenever the expandedIndex changes - useEffect(() => { - if (expandedIndex !== null) { - setRenderCycle(0); - } - }, [expandedIndex]); - - // Effect to handle scrolling to the expanded item after the DOM has updated - useEffect(() => { - if (renderCycle < 3) { - // Increment render cycle count to ensure multiple render checks - setRenderCycle((prev) => prev + 1); - } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { - try { - const parentElement = itemRefs.current[expandedIndex]; - const childElement = itemRefs.current[expandedIndex].children[1]; - - if (parentElement) { - const scrollContainer = scrollContainerRef.current; - const parentRect = parentElement.getBoundingClientRect(); - const containerRect = scrollContainer.getBoundingClientRect(); - - // Calculate the offset from the top of the container - const offset = parentRect.top - containerRect.top; - - // Scroll the container to the target position - scrollContainer.scrollTo({ - top: scrollContainer.scrollTop + offset - 100, - behavior: "smooth", - }); - } - - if (childElement) { - // Focus the child element if it exists - childElement.focus(); - } - } catch (error) { - console.error("Error scrolling to element:", error); - } - } - }, [renderCycle, expandedIndex]); - - // Effect to observe DOM changes in the expanded item and trigger render cycle - useEffect(() => { - if (expandedIndex !== null) { - const observer = new MutationObserver(() => { - setRenderCycle((prev) => prev + 1); - }); - - if (itemRefs.current[expandedIndex]) { - observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); - } - - return () => observer.disconnect(); - } - }, [expandedIndex]); - - // Function to toggle the expanded state of an item - const toggleExpand = (index) => { - setExpandedIndex(index === expandedIndex ? null : index); - }; - - // Handler for deleting an assumption on conformation - const deleteHandler = useCallback( - (item) => { - setModal("delete-conformation"); - setItemForDeletion(item); - }, - [setModal, setItemForDeletion] - ); - - return ( -
- -
-
-
-

{t("VALUE")}

-
-
=
-
-

{t("RULE_ENGINE_INPUT")}

-
-
-

{t("RULE_ENGINE_OPERATOR")}

-
-
-

{t("KEY")}

-
-
- -
-
- {rules - .filter((item) => item.active) - .map((item, index) => ( -
{ - itemRefs.current[index] = el; - }} - onClick={() => toggleExpand(index)} - > -
- -
-
- -
-
- -
-
- ))} -
-
- ); - } -); - -const Example = ({ exampleOption, t }) => { - return ( -
-
-

{t("EXAMPLE")}

-
-
-

{t("VALUE")}

- -

{t("RULE_ENGINE_VALUE_HELP_TEXT")}

-
- -
-

{"="}

- -
=
-

{"="}

-
- -
-

{t("RULE_ENGINE_INPUT")}

- -

{t("RULE_ENGINE_INPUT_HELP_TEXT")}

-
-
-

{t("RULE_ENGINE_OPERATOR")}

- -

{t("RULE_ENGINE_OPERATOR_HELP_TEXT")}

-
-
-

{t("KEY")}

- -

{t("RULE_ENGINE_KEY_HELP_TEXT")}

-
-
-
-
- -
-
- ); -}; - -const deleteAssumptionHandler = (item, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList) => { - try { - const outputToRemove = []; - setRules((previous) => { - if (!previous.length) return []; - const deletionElementIndex = previous.findIndex((data) => data.id === item.id); - const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data)); - const newRules = filteredData.reduce((acc, dataItem, index) => { - if (dataItem.active) { - const possibleOutputs = acc.reduce((reducedData, element, index) => { - if (element.active && !Object.values(element).some((e) => e === "")) reducedData.push(element?.output); - return reducedData; - }, []); - possibleOutputs.push(...pureInputList); - if (!possibleOutputs.includes(dataItem?.input)) { - if (dataItem?.output !== "") outputToRemove.push(dataItem.output); - acc.push({ ...dataItem, input: "", oldInput: dataItem?.input ? dataItem?.input : dataItem?.oldInput }); - } else { - acc.push(dataItem); - } - } else { - acc.push(dataItem); - } - return acc; - }, []); - - return newRules || []; - }); - if (item?.output) { - setOutputs((previous) => { - if (!previous?.includes(item.output)) return previous ? [...previous, item.output] : [item.output]; - }); - setInputs((previous) => { - return previous?.filter((e) => e !== item.output && !outputToRemove.includes(e)); - }); - } - setItemForDeletion(); - } catch (error) { - console.error("Error while deleting a rule: ", error.message); - } -}; - -const Select = React.memo( - ({ item, rules, setRules, disabled = false, options, setOptions, toChange, unique, setInputs, outputs, pureInputList, t }) => { - const [selected, setSelected] = useState(""); - const [filteredOptions, setFilteredOptions] = useState([]); - - useEffect(() => { - if (item) { - if (outputs?.some((e) => e === item.input)) { - if (rules.filter((item) => item.active).some((e) => e?.output === item?.input)) setSelected({ code: item?.[toChange] }); - } else setSelected({ code: item[toChange] }); - } - }, [item]); - - useEffect(() => { - if (!options) return; - const filteredOptions = options.length ? options : []; - let filteredOptionPlaceHolder = []; - if (item?.[toChange] && !filteredOptions.includes(item[toChange])) { - filteredOptionPlaceHolder = [item[toChange], ...filteredOptions]; - } else filteredOptionPlaceHolder = filteredOptions; - - if (toChange === "input") { - const currentRuleIndex = rules.findIndex((e) => e?.id === item?.id); - filteredOptionPlaceHolder = filteredOptionPlaceHolder.filter((data) => { - let priorOutputs = []; - if (currentRuleIndex !== -1) { - priorOutputs = rules.reduce((acc, item, index) => { - if (item.active && index < currentRuleIndex) acc.push(item?.output); - return acc; - }, []); - } - priorOutputs.push(...pureInputList); - return data !== item.output && priorOutputs.includes(data); - }); - } - setFilteredOptions(filteredOptionPlaceHolder); - }, [options]); - - const selectChangeHandler = useCallback( - (e) => { - if (e.code === "SELECT_OPTION") return; - const existingEntry = rules.find((item) => item.active && item[toChange] === e.code); - if (existingEntry && unique) { - console.error("Attempted to add a duplicate entry where uniqueness is required."); - return; - } - const newDataSegment = { ...item }; - newDataSegment[toChange] = e.code; - setRules((previous) => { - const filteredAssumptionsList = previous.map((data) => { - if (data.id === item.id) return newDataSegment; - return data; - }); - return filteredAssumptionsList; - }); - if (typeof setInputs === "function") { - setInputs((previous) => { - let temp = _.cloneDeep(previous); - if (toChange === "output") { - temp = temp.filter((item) => item !== selected?.code); - } - if (!temp.includes(newDataSegment.output) && Object.values(newDataSegment).every((item) => item !== "")) - temp = [...temp, newDataSegment.output]; - - const currentRuleIndex = rules.findIndex((e) => e?.id === item?.id); - temp = temp.filter((data) => { - let priorOutputs = []; - if (currentRuleIndex !== -1) { - priorOutputs = rules.reduce((acc, item, index) => { - if (index < currentRuleIndex) acc.push(item?.output); - return acc; - }, []); - } - priorOutputs.push(...pureInputList); - return data !== item.output && priorOutputs.includes(data); - }); - return temp; - }); - } - if (unique) - setOptions((previous) => { - const newOptions = previous.filter((item) => item !== e.code); - if (selected?.code && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code); - return newOptions; - }); - }, - [rules, item, selected, setRules, setOptions, setInputs] - ); - - return ( - ({ code: item }))} - selected={selected} - select={selectChangeHandler} - optionKey="code" - placeholder={t("SELECT_OPTION")} - showToolTip={true} - /> - ); - } -); - -// get schema for validation -const getRuleConfigInputsFromSchema = (campaignType, microplanData, schemas) => { - if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; - const sortData = []; - if (!schemas) return; - for (const value of microplanData?.upload?.filter((value) => value?.active && value?.error === null) || []) { - sortData.push({ section: value?.section, fileType: value?.fileType }); - } - const filteredSchemas = - schemas?.filter((schema) => { - if (schema.campaignType) { - return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); - } - return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); - }) || []; - const finalData = filteredSchemas - ?.flatMap((item) => - Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRuleConfigureInputs) { - acc.push(key); - } - return acc; - }, []) - ) - .filter((item) => !!item); - return [...new Set(finalData)]; -}; - -// This function adding the rules configures in MDMS with respect to the canpaign when rule section is empty -const filterRulesAsPerConstrains = (autofillData, rules, hypothesisAssumptionsList, outputs, operators, inputs, setInputs, setOutputs, autofill) => { - if (rules && rules.filter((item) => item.active).length !== 0) return { rules }; - - let wereRulesNotDeleted = true; - const newRules = []; - const ruleOuputList = rules ? rules.filter((item) => item.active).map((item) => item?.output) : []; - let rulePlusInputs; - if (ruleOuputList) rulePlusInputs = [...inputs, ...ruleOuputList]; - else rulePlusInputs = inputs; - for (const item of autofillData) { - let active = !(item && item.active === false); - const ruleNotCompleteCheck = (!autofill && item && Object.values(item).filter((e) => e === "").length === 0) || autofill; - if ( - (ruleOuputList?.includes(item?.output) || - (outputs && !outputs.includes(item?.output)) || - (rulePlusInputs && !rulePlusInputs.includes(item?.input)) || - (operators && !operators.includes(item?.operator)) || - (hypothesisAssumptionsList && !hypothesisAssumptionsList.includes(item?.assumptionValue)) || - !outputs || - !rulePlusInputs || - !operators || - !hypothesisAssumptionsList) && - ruleNotCompleteCheck - ) { - if (autofill) { - continue; - } - if (active) { - wereRulesNotDeleted = false; - active = false; - } - } - if (!item["id"]) { - const uuid = uuidv4(); - item["id"] = uuid; - } - item.active = active; - newRules.push(item); - if (active && ruleNotCompleteCheck) { - rulePlusInputs?.push(item?.output); - ruleOuputList?.push(item?.output); - } - } - if (newRules.length !== 0) { - let newOutputs = []; - outputs.forEach((e) => { - if (!ruleOuputList.includes(e)) { - newOutputs.push(e); - } - }); - setOutputs(newOutputs); - setInputs(rulePlusInputs); - // setRules((previous) => [...previous, ...newRules]); - } - - return { rules: [...(rules ? rules : []), ...newRules], rulesDeleted: !autofill && !wereRulesNotDeleted }; -}; - -export default RuleEngine; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js deleted file mode 100644 index e6309dd74f3..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js +++ /dev/null @@ -1,1137 +0,0 @@ -import React, { useState, useEffect, useMemo, Fragment, useCallback } from "react"; -import { useTranslation } from "react-i18next"; -import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import { ModalWrapper } from "./Modal"; -import { geojsonPropertiesValidation } from "../utils/geojsonValidations"; -import { SpatialDataPropertyMapping } from "./resourceMapping"; -import { JsonPreviewInExcelForm } from "./JsonPreviewInExcelForm"; -import { ButtonType1, ButtonType2, CloseButton, ModalHeading } from "./CommonComponents"; -import { Loader } from "@egovernments/digit-ui-components"; -import { EXCEL, FILE_STORE, GEOJSON, PRIMARY_THEME_COLOR, SHAPEFILE } from "../configs/constants"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { v4 as uuidv4 } from "uuid"; -import { - handleExcelFile, - validateNamingConvention, - findReadMe, - downloadTemplate, - getSchema, - prepareExcelFileBlobWithErrors, - boundaryDataGeneration, - handleGeojsonFile, - handleShapefiles, - convertToSheetArray, - findGuideLine, - delay, -} from "../utils/uploadUtils"; -import { UploadGuideLines, UploadedFile, FileUploadComponent, UploadComponents, UploadInstructions, UploadSection } from "./UploadHelperComponents"; - -const page = "upload"; - -const Upload = ({ - MicroplanName = "default", - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - navigationEvent, - setToast, -}) => { - const { t } = useTranslation(); - - // States - const [editable, setEditable] = useState(true); - const [sections, setSections] = useState([]); - const [selectedSection, setSelectedSection] = useState(null); - const [modal, setModalState] = useState("none"); - const [selectedFileType, setSelectedFileType] = useState(null); - const [dataPresent, setDataPresent] = useState(false); - const [dataUpload, setDataUpload] = useState(false); - const [loader, setLoader] = useState(false); - const [fileData, setFileData] = useState(); - const [uploadedFileError, setUploadedFileError] = useState(); - const [fileDataList, setFileDataList] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [template, setTemplate] = useState([]); - const [resourceMapping, setResourceMapping] = useState([]); - const [previewUploadedData, setPreviewUploadedData] = useState(); - const { state, dispatch } = useMyContext(); - - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - - // request body for boundary hierarchy api - const reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getCurrentTenantId(), - hierarchyType: campaignData?.hierarchyType, - // hierarchyType: "Microplan", - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return ( - data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map( - (item) => `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}` - ) || {} - ); - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, [t]); - - const setModal = (modalString) => { - const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); - elements.forEach((element) => { - element.classList.toggle("popup-wrap-rest-unfocus-active"); - }); - setModalState(modalString); - }; - - // UseEffect for checking completeness of data before moveing to next section - useEffect(() => { - if (!fileDataList || checkDataCompletion !== "true" || !setCheckDataCompletion) return; - updateData(true); - }, [checkDataCompletion]); - - // UseEffect to store current data - useEffect(() => { - if (!fileDataList || !setMicroplanData) return; - setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); - }, [fileDataList]); - - // check if data has changed or not - const updateData = useCallback( - (check) => { - if (!fileDataList || !setMicroplanData) return; - - // if user has selected a file type and wants to go back to file type selection he/she can click back buttom - const currentSectionIndex = sections.findIndex((item) => item.id === selectedSection.id); - if (!dataPresent) { - if (navigationEvent?.name !== "step") { - if (navigationEvent?.name === "next") { - if (currentSectionIndex < sections.length - 1) { - setSelectedSection(sections[currentSectionIndex + 1]); - setCheckDataCompletion("false"); - return; - } - } else if (navigationEvent?.name === "previousStep") { - if (dataUpload) { - setDataUpload(false); - setSelectedFileType(null); - setCheckDataCompletion("false"); - return; - } - if (currentSectionIndex > 0) { - setSelectedSection(sections[currentSectionIndex - 1]); - setCheckDataCompletion("false"); - return; - } - } - } - } else { - if (navigationEvent?.name === "next") { - if (currentSectionIndex < sections.length - 1) { - setSelectedSection(sections[currentSectionIndex + 1]); - setCheckDataCompletion("false"); - return; - } - } else if (navigationEvent?.name === "previousStep") { - if (currentSectionIndex > 0) { - setSelectedSection(sections[currentSectionIndex - 1]); - setCheckDataCompletion("false"); - return; - } - } - } - - if (check) { - setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); - const valueList = fileDataList ? fileDataList : []; - const sectionCheckList = sections?.filter((item) => item.required); - - if ( - valueList.length !== 0 && - sectionCheckList.every((item) => { - const filteredList = fileDataList?.filter((e) => e.active && e.templateIdentifier === item.id); - if (filteredList?.length === 0) return false; - return filteredList?.every((element) => element?.error === null) && fileDataList && !fileDataList.some((e) => e?.active && e?.error); - }) - ) - setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } else { - const valueList = microplanData?.Upload ? Object.values(microplanData?.Upload) : []; - if ( - valueList.length !== 0 && - sectionCheckList.every((item) => - fileDataList?.filter((e) => e.templateIdentifier === item.id)?.every((element) => element.active && element?.error === null) - ) - ) - setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } - }, - [fileDataList, setMicroplanData, microplanData, setCheckDataCompletion, dataPresent, dataUpload, navigationEvent] - ); - - // UseEffect to extract data on first render - useEffect(() => { - if (microplanData?.upload) { - setFileDataList(microplanData.upload); - } - - if (pages) { - const previouspage = pages[currentPage?.id - 1]; - if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); - else setEditable(true); - } - }, []); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal, previewUploadedData]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - if (modal === "upload-guidelines") { - setModal("none"); - } - if (previewUploadedData) setPreviewUploadedData(undefined); - } - }; - - // Effect to update sections and selected section when data changes - useEffect(() => { - if (state) { - const uploadSections = state?.UploadConfiguration; - const schemas = state?.Schemas; - if (schemas) setValidationSchemas(schemas); - if (uploadSections) { - setSelectedSection(uploadSections.length > 0 ? uploadSections[0] : null); - setSections(uploadSections); - } - } - }, []); - - // Memoized section options to prevent unnecessary re-renders - const sectionOptions = useMemo(() => { - if (!sections) return []; - return sections.map((item) => ( - e.active && e.templateIdentifier === item.id && !e.error)?.length !== 0} - /> - )); - }, [sections, selectedSection, fileDataList]); - - const showDownloadTemplate = () => { - if (selectedSection?.UploadFileTypes) { - const schema = getSchema(campaignType, selectedFileType?.id, selectedSection.id, validationSchemas); - if (schema?.template?.showTemplateDownload) return true; - } - return false; - }; - - // Handler for when a file type is selected for uplaod - const selectFileTypeHandler = (e) => { - if (selectedSection?.UploadFileTypes) { - const schema = getSchema(campaignType, e.target.name, selectedSection.id, validationSchemas); - setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item.id === e.target.name)); - if (schema?.template?.showTemplateDownload) setModal("upload-modal"); - else UploadFileClickHandler(false); - return; - } - setToast({ - state: "error", - message: t("ERROR_UNKNOWN"), - }); - setLoader(false); - return; - }; - - // Memoized section components to prevent unnecessary re-renders - const sectionComponents = useMemo(() => { - if (!sections) return; - return sections.map((item) => ( - - )); - }, [sections, selectedSection, selectedFileType]); - - // Close model click handler - const closeModal = () => { - setResourceMapping([]); - setModal("none"); - }; - - // handler for show file upload screen - const UploadFileClickHandler = (download = false) => { - if (download) { - downloadTemplateHandler(); - } - setModal("none"); - setDataUpload(true); - }; - const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); - const downloadTemplateHandler = () => { - const downloadParams = { - campaignType, - type: selectedFileType.id, - section: selectedSection.id, - setToast, - campaignData, - hierarchyType: campaignData?.hierarchyType, - Schemas: validationSchemas, - HierarchyConfigurations: state?.HierarchyConfigurations, - setLoader, - hierarchy, - readMeData: state?.ReadMeData, - readMeSheetName: readMeConstant ? readMeConstant.value : undefined, - t, - }; - downloadTemplate(downloadParams); - }; - // Effect for updating current session data in case of section change - useEffect(() => { - if (selectedSection) { - let file = fileDataList?.find((item) => item.active && item.templateIdentifier === selectedSection.id); - if (file?.resourceMapping) { - setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item?.id === file?.fileType)); - setUploadedFileError(file?.error); - setFileData(file); - setDataPresent(true); - } else { - resetSectionState(); - } - } else { - resetSectionState(); - } - }, [selectedSection]); - - const resetSectionState = () => { - setUploadedFileError(null); - setSelectedFileType(null); - setDataPresent(false); - setResourceMapping([]); - setDataUpload(false); - }; - - // Function for handling upload file event - const UploadFileToFileStorage = async (file) => { - if (!file) return; - try { - // setting loader - setLoader("FILE_UPLOADING"); - let check; - let fileDataToStore; - let errorMsg; - let errorLocationObject; // object containing the location and type of error - let response; - let callMapping = false; - // Checking if the file follows name convention rules - if (!validateNamingConvention(file, selectedFileType["namingConvention"], setToast, t)) { - setLoader(false); - return; - } - - let schemaData; - if (selectedFileType.id !== SHAPEFILE) { - // Check if validation schema is present or not - schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - if (!schemaData) { - setToast({ - state: "error", - message: t("ERROR_VALIDATION_SCHEMA_ABSENT"), - }); - setLoader(false); - return; - } - } - let resourceMappingData = []; - let additionalSheets = []; - // Handling different filetypes - switch (selectedFileType.id) { - case EXCEL: - // let response = handleExcelFile(file,schemaData); - try { - response = await handleExcelFile( - file, - schemaData, - hierarchy, - selectedFileType, - {}, - setUploadedFileError, - t, - campaignData, - state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value - ); - check = response.check; - errorMsg = response.errorMsg; - errorLocationObject = response.errors; - fileDataToStore = response.fileDataToStore; - resourceMappingData = response?.tempResourceMappingData || []; - additionalSheets = response?.additionalSheets; - if (check === true) { - if (response?.toast) setToast(response.toast); - else setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); - } else if (response.toast) { - setToast(response.toast); - } else { - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - } - if (response.interruptUpload) { - setLoader(false); - return; - } - } catch (error) { - console.error("Excel parsing error", error.message); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); - return; - } - break; - case GEOJSON: - try { - response = await handleGeojsonFile(file, schemaData, setUploadedFileError, t); - file = new File([file], file.name, { type: "application/geo+json" }); - if (response.check === false && response.stopUpload) { - setLoader(false); - setToast(response.toast); - return; - } - check = response.check; - errorMsg = response.error; - fileDataToStore = response.fileDataToStore; - callMapping = true; - } catch (error) { - // console.error("Geojson parsing error", error.message); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); - return; - } - break; - case SHAPEFILE: - try { - response = await handleShapefiles(file, schemaData, setUploadedFileError, selectedFileType, setToast, t); - file = new File([file], file.name, { type: "application/octet-stream" }); - check = response.check; - errorMsg = response.error; - fileDataToStore = response.fileDataToStore; - callMapping = true; - } catch (error) { - console.error("Shapefile parsing error", error.message); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); - return; - } - break; - default: - setToast({ - state: "error", - message: t("ERROR_UNKNOWN_FILETYPE"), - }); - setLoader(false); - return; - } - let filestoreId; - if (!errorMsg && !callMapping) { - try { - const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, file, Digit.ULBService.getCurrentTenantId()); - if (filestoreResponse?.data?.files?.length > 0) { - filestoreId = filestoreResponse?.data?.files[0]?.fileStoreId; - } else { - errorMsg = t("ERROR_UPLOADING_FILE"); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setFileData((previous) => ({ ...previous, error: errorMsg })); - setUploadedFileError(errorMsg); - } - } catch (errorData) { - console.error(errorData.message); - errorMsg = t("ERROR_UPLOADING_FILE"); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setUploadedFileError(errorMsg); - handleValidationErrorResponse(t("ERROR_UPLOADING_FILE")); - return; - } - } - - if (selectedFileType.id === EXCEL) { - resourceMappingData = resourceMappingData.map((item) => ({ ...item, filestoreId })); - } - const uuid = uuidv4(); - // creating a fileObject to save all the data collectively - let fileObject = { - id: uuid, - templateIdentifier: `${selectedSection.id}`, - fileName: file.name, - section: selectedSection.id, - fileType: selectedFileType.id, - data: fileDataToStore, - file, - error: errorMsg ? errorMsg : null, - filestoreId, - resourceMapping: resourceMappingData, - active: true, - additionalSheets, - errorLocationObject, // contains location and type of error - }; - setFileDataList((prevFileDataList) => { - let temp = _.cloneDeep(prevFileDataList); - if (!temp) return temp; - let index = prevFileDataList?.findIndex((item) => item.active && item.templateIdentifier === selectedSection.id); - if (index !== -1) - temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; - temp.push(fileObject); - return temp; - }); - setFileData(fileObject); - if (errorMsg === undefined && callMapping) { - setModal("spatial-data-property-mapping"); - } - setDataPresent(true); - setLoader(false); - } catch (error) { - console.error(error.message); - console.error("File Upload error", error?.message); - setUploadedFileError("ERROR_UPLOADING_FILE"); - setLoader(false); - } - }; - - // Reupload the selected file - const reuplaodFile = () => { - setResourceMapping([]); - setFileData(undefined); - setDataPresent(false); - setUploadedFileError(null); - setDataUpload(false); - setSelectedFileType(null); - closeModal(); - }; - - const convertAndCombineFileData = () => { - let combinedData = fileData?.data ? Object.entries(fileData.data)?.map(([key, value]) => ({ sheetName: key, data: value })) : []; - if (fileData?.additionalSheets) { - for (const sheet of fileData.additionalSheets) { - if (sheet?.data && sheet.sheetName) { - const index = sheet?.position < combinedData.length && sheet.position !== -1 ? sheet.position : combinedData.length; - combinedData.splice(index, 0, sheet); - } - } - } - return combinedData; - }; - - // Function for creating blob out of data - const dataToBlob = async () => { - try { - let blob; - const schema = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - const filteredReadMeData = findReadMe(state?.ReadMeData, campaignType, selectedFileType.id, selectedSection.id); - let combinedData = convertAndCombineFileData(); - const readMeSheetName = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value; - switch (fileData.fileType) { - case EXCEL: - if (fileData?.errorLocationObject?.length !== 0) - blob = await prepareExcelFileBlobWithErrors( - combinedData, - fileData.errorLocationObject, - schema, - hierarchy, - filteredReadMeData, - readMeSheetName, - t - ); - else blob = fileData.file; - break; - case SHAPEFILE: - case GEOJSON: - if (fileData?.data) { - const result = convertToSheetArray(Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section)); - - if (fileData?.errorLocationObject?.length !== 0) - blob = await prepareExcelFileBlobWithErrors( - result, - fileData.errorLocationObject, - schema, - hierarchy, - filteredReadMeData, - readMeSheetName, - t - ); - } - break; - } - return blob; - } catch (error) { - console.error("Error generating blob:", error); - return; - } - }; - - // Download the selected file - const downloadFile = async () => { - setLoader("LOADING"); - try { - await delay(100); - let blob = await dataToBlob(); - if (blob) { - // Crating a url object for the blob - const url = URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - - // Forming a name for downloaded file - let fileNameParts = fileData.fileName.split("."); - fileNameParts.pop(); - fileNameParts.push("xlsx"); - fileNameParts.join("."); - - //Downloading the file - link.download = fileNameParts.join("."); - link.click(); - URL.revokeObjectURL(url); - } else { - let downloadUrl = await Digit.UploadServices.Filefetch([fileData.filestoreId], Digit.ULBService.getCurrentTenantId()); - const link = document.createElement("a"); - link.href = downloadUrl; - // Forming a name for downloaded file - let fileNameParts = fileData.fileName.split("."); - fileNameParts.pop(); - fileNameParts.push("xlsx"); - fileNameParts.join("."); - link.download = fileNameParts; // Replace with the desired file name and extension - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - } - } catch (error) { - console.error(error.message); - setToast({ - state: "error", - message: t("ERROR_UNKNOWN_ERROR"), - }); - } - setLoader(false); - }; - - // delete the selected file - const deleteFile = () => { - setResourceMapping([]); - setFileDataList((previous) => { - let temp = _.cloneDeep(previous); - if (!temp) return temp; - let index = temp?.findIndex((item) => { - return item.id === fileData.id; - }); - if (index !== -1) - temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; - return temp; - }); - setFileData(undefined); - setDataPresent(false); - setUploadedFileError(null); - setDataUpload(false); - setSelectedFileType(null); - closeModal(); - }; - - // Function for handling the validations for geojson and shapefiles after mapping of properties - const validationForMappingAndDataSaving = async () => { - try { - setLoader("LOADING"); - const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - let error; - if (!checkForSchemaData(schemaData)) return; - const { data, valid, errors } = computeMappedDataAndItsValidations(schemaData); - error = errors; - if (!valid) return; - let filestoreId; - if (!error) { - filestoreId = await saveFileToFileStore(); - } - let resourceMappingData; - if (filestoreId) { - resourceMappingData = resourceMapping.map((item) => { - return { ...item, filestoreId }; - }); - } - setResourceMapping([]); - - let boundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; - const mappedToList = resourceMappingData.map((item) => item.mappedTo); - if (hierarchy.every((item) => !mappedToList.includes(t(item)))) { - data.features.forEach((feature) => { - const boundaryCode = feature.properties.boundaryCode; - let additionalDetails = {}; - for (let i = 0; i < hierarchy.length; i++) { - if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { - additionalDetails[hierarchy[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; - } else { - additionalDetails[hierarchy[i]] = ""; - } - } - feature.properties = { ...additionalDetails, ...feature.properties }; - }); - } - - let fileObject = _.cloneDeep(fileData); - fileObject = { ...fileData, data, resourceMapping: resourceMappingData, error: error ? error : null, filestoreId }; - setFileData(fileObject); - setFileDataList((prevFileDataList) => { - let temp = _.cloneDeep(prevFileDataList); - if (!temp) return temp; - let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); - if (index !== -1) temp[index] = fileObject; - // temp.push(fileObject); - return temp; - }); - - setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); - setLoader(false); - } catch (error) { - console.error(error.message); - setUploadedFileError(t("ERROR_UPLOADING_FILE")); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setLoader(false); - handleValidationErrorResponse("ERROR_UPLOADING_FILE"); - } - }; - const saveFileToFileStore = async () => { - try { - const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, fileData.file, Digit.ULBService.getCurrentTenantId()); - if (filestoreResponse?.data?.files?.length > 0) { - return filestoreResponse?.data?.files[0]?.fileStoreId; - } - error = t("ERROR_UPLOADING_FILE"); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setResourceMapping([]); - setUploadedFileError(error); - } catch (errorData) { - console.error("Error while uploading file to filestore: ", errorData?.message); - let error = t("ERROR_UPLOADING_FILE"); - handleValidationErrorResponse(error); - setResourceMapping([]); - return; - } - }; - const computeMappedDataAndItsValidations = (schemaData) => { - const data = computeGeojsonWithMappedProperties(); - const response = geojsonPropertiesValidation(data, schemaData.schema, fileData?.section, t); - if (!response.valid) { - handleValidationErrorResponse(response.message, response.errors); - return { data: data, errors: response.errors, valid: response.valid }; - } - return { data: data, valid: response.valid }; - }; - - const handleValidationErrorResponse = (error, errorLocationObject = {}) => { - const fileObject = fileData; - if (fileObject) { - fileObject.error = [error]; - if (errorLocationObject) fileObject.errorLocationObject = errorLocationObject; - setFileData((previous) => ({ ...previous, error, errorLocationObject })); - setFileDataList((prevFileDataList) => { - let temp = _.cloneDeep(prevFileDataList); - if (!temp) return temp; - let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); - temp[index] = fileObject; - return temp; - }); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - if (error) setUploadedFileError(error); - } - setLoader(false); - }; - - const checkForSchemaData = (schemaData) => { - if (resourceMapping?.length === 0) { - setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); - setLoader(false); - return false; - } - - if (!schemaData || !schemaData.schema || !schemaData.schema["Properties"]) { - setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") }); - setLoader(false); - return; - } - - let columns = []; - if (schemaData?.doHierarchyCheckInUploadedData) { - columns.push(...hierarchy); - } - columns.push( - ...Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRequired) { - acc.push(key); - } - return acc; - }, []) - ); - - const resourceMappingLength = resourceMapping.filter((e) => !!e?.mappedFrom && columns.includes(e?.mappedTo)).length; - if (resourceMappingLength !== columns?.length) { - setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); - setLoader(false); - return false; - } - setModal("none"); - return true; - }; - - const computeGeojsonWithMappedProperties = () => { - const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - let schemaKeys; - if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"])); - // Sorting the resourceMapping list inorder to maintain the column sequence - const sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); - // Creating a object with input data with MDMS keys - const newFeatures = fileData.data["features"].map((item) => { - let newProperties = {}; - - sortedSecondList.forEach((e) => { - newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; - }); - item["properties"] = newProperties; - return item; - }); - let data = fileData.data; - data["features"] = newFeatures; - return data; - }; - - // Handler for checing file extension and showing errors in case it is wrong - const onTypeErrorWhileFileUpload = () => { - switch (selectedFileType.id) { - case EXCEL: - setToast({ state: "error", message: t("ERROR_EXCEL_EXTENSION") }); - break; - case GEOJSON: - setToast({ state: "error", message: t("ERROR_GEOJSON_EXTENSION") }); - break; - case SHAPEFILE: - setToast({ state: "error", message: t("ERROR_SHAPE_FILE_EXTENSION") }); - break; - } - }; - - // Cancle mapping and uplaod in case of geojson and shapefiles - const cancelUpload = () => { - setFileDataList((previous) => { - let temp = previous?.filter((item) => item.id !== fileData?.id); - return temp; - }); - setFileData(undefined); - setDataPresent(false); - setUploadedFileError(null); - setDataUpload(false); - setSelectedFileType(null); - closeModal(); - }; - - const openDataPreview = () => { - let data; - switch (fileData.fileType) { - case EXCEL: - data = fileData.data; - break; - case SHAPEFILE: - case GEOJSON: - if (!fileData || !fileData.data) { - setToast({ - state: "error", - message: t("ERROR_DATA_NOT_PRESENT"), - }); - return; - } - data = Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section); - break; - } - if (!data || Object.keys(data).length === 0) { - setToast({ - state: "error", - message: t("ERROR_DATA_NOT_PRESENT"), - }); - return; - } - setPreviewUploadedData(data); - }; - - if (isCampaignLoading || ishierarchyLoading) { - return ( -
- -
- ); - } - - return ( - <> -
-
-
- {!dataPresent ? ( - dataUpload ? ( -
- e.id === selectedSection.id)[0]} - selectedSection={selectedSection} - selectedFileType={selectedFileType} - UploadFileToFileStorage={UploadFileToFileStorage} - onTypeError={onTypeErrorWhileFileUpload} - downloadTemplateHandler={downloadTemplateHandler} - showDownloadTemplate={showDownloadTemplate} - /> -
- ) : ( -
{sectionComponents}
- ) - ) : ( -
- {selectedSection != null && fileData !== null && ( - { - setModal("reupload-conformation"); - }} - DownloadFile={downloadFile} - DeleteFile={() => { - setModal("delete-conformation"); - }} - error={uploadedFileError} - openDataPreview={openDataPreview} - downloadTemplateHandler={downloadTemplateHandler} - showDownloadTemplate={showDownloadTemplate} - /> - )} -
- )} - {!dataPresent && dataUpload && ( - { - setModal("upload-guidelines"); - }} - t={t} - /> - )} -
- -
{sectionOptions}
-
- -
- {modal === "upload-modal" && ( - { - closeModal(); - setSelectedFileType(null); - }} - LeftButtonHandler={() => UploadFileClickHandler(false)} - RightButtonHandler={() => UploadFileClickHandler(true)} - sections={sections} - popupModuleActionBarStyles={{ - flex: 1, - justifyContent: "space-between", - padding: "1rem", - gap: "1rem", - }} - footerLeftButtonBody={} - footerRightButtonBody={} - header={ - - } - bodyText={t(`INSTRUCTIONS_DOWNLOAD_TEMPLATE_FOR_${selectedSection.code}_${selectedFileType.code}`)} - /> - )} - {modal === "delete-conformation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={deleteFile} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={closeModal} - > -
-

{t("INSTRUCTIONS_DELETE_FILE_CONFIRMATION")}

-
-
- )} - {modal === "reupload-conformation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={reuplaodFile} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={closeModal} - > -
-

{t("INSTRUCTIONS_REUPLOAD_FILE_CONFIRMATION")}

-
-
- )} - {modal === "spatial-data-property-mapping" && ( - } - actionSaveOnSubmit={validationForMappingAndDataSaving} - actionSaveLabel={t("COMPLETE_MAPPING")} - headerBarEnd={} - > -
-

{t("INSTRUCTION_SPATIAL_DATA_PROPERTY_MAPPING")}

-
- -
- )} - {modal === "upload-guidelines" && ( - - } - headerBarEnd={} - > - - - )} - {loader && } - - {previewUploadedData && ( -
- setPreviewUploadedData(undefined)} - onDownload={downloadFile} - /> -
- )} -
-
- - ); -}; - -export default Upload; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js deleted file mode 100644 index 5a520c4a1bd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js +++ /dev/null @@ -1,299 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import * as Icons from "@egovernments/digit-ui-svg-components"; -import { FileUploader } from "react-drag-drop-files"; -import { InfoButton, InfoCard } from "@egovernments/digit-ui-components"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; - -// Component for rendering individual section option -export const UploadSection = ({ item, selected, setSelectedSection, uploadDone }) => { - const { t } = useTranslation(); - // Handle click on section option - const handleClick = () => { - setSelectedSection(item); - }; - - return ( -
-
- -
-

{t(item.code)}

- {uploadDone && ( -
- -
- )} -
- ); -}; - -export const UploadInstructions = ({ setModal, t }) => { - return ( - - {t("REFER")} -
- {t("INFORMATION_DESCRIPTION_LINK")} -
-
, - ]} - /> - ); -}; - -// Component for rendering individual upload option -export const UploadComponents = ({ item, selected, uploadOptions, selectedFileType, selectFileTypeHandler }) => { - const { t } = useTranslation(); - const title = item.code; - - // Component for rendering individual upload option container - const UploadOptionContainer = ({ item, selectedFileType, selectFileTypeHandler }) => { - const [isHovered, setIsHovered] = useState(false); - - const handleMouseEnter = () => { - setIsHovered(true); - }; - - const handleMouseLeave = () => { - setIsHovered(false); - }; - - return ( -
- -

{t(item.code)}

- -
- ); - }; - - return ( -
-
-
-

{t(`HEADING_UPLOAD_DATA_${title}`)}

-
- -

{t(`INSTRUCTIONS_DATA_UPLOAD_OPTIONS_${title}`)}

-
-
- {uploadOptions?.map((item) => ( - - ))} -
-
- ); -}; - -// Component for uploading file -export const FileUploadComponent = ({ - selectedSection, - selectedFileType, - UploadFileToFileStorage, - section, - onTypeError, - downloadTemplateHandler, - showDownloadTemplate, -}) => { - if (!selectedSection || !selectedFileType) return
; - const { t } = useTranslation(); - let types; - section["UploadFileTypes"].forEach((item) => { - if (item.id === selectedFileType.id) types = item.fileExtension; - }); - return ( -
-
-
-

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

- {showDownloadTemplate() && ( - - )} -
-

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

- -
- -
- {t(`INSTRUCTIONS_UPLOAD_${selectedFileType.code}`)} 
{t("INSTRUCTIONS_UPLOAD_BROWSE_FILES")}
-
-
-
-
-
- ); -}; - -// Component to display uploaded file -export const UploadedFile = ({ - selectedSection, - selectedFileType, - file, - ReuplaodFile, - DownloadFile, - DeleteFile, - error, - openDataPreview, - downloadTemplateHandler, - showDownloadTemplate, -}) => { - const { t } = useTranslation(); - const [errorList, setErrorList] = useState([]); - useEffect(() => { - let tempErrorList = []; - if (file?.errorLocationObject) { - for (const [sheetName, values] of Object.entries(file?.errorLocationObject)) { - for (const [row, columns] of Object.entries(values)) { - for (const [column, errors] of Object.entries(columns)) { - for (const error of errors) { - let convertedError; - if (typeof error === "object") { - let { error: actualError, ...otherProperties } = error; - convertedError = t(actualError, otherProperties?.values); - } else { - convertedError = t(error); - } - tempErrorList.push( - t("ERROR_UPLOAD_DATA_LOCATION_AND_MESSAGE", { - rowNumber: Number(row) + 1, - columnName: t(column), - error: convertedError, - sheetName: sheetName, - }) - ); - } - } - } - } - } - if (tempErrorList.length !== 0) { - setErrorList(tempErrorList); - } - }, [file]); - return ( -
-
-
-

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

- {showDownloadTemplate() && ( - - )} -
-

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

- -
-
-
- -
-

{file.fileName}

-
-
- - - -
-
-
- {error && Array.isArray(error) && ( - , -
- {error?.map((item) => { - if (item !== "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") { - return

{t(item)}

; - } - return null; - })} - {errorList.length !== 0 && errorList.map((item) =>

{item}

)} -
, - ]} - /> - )} -
- ); -}; - -// Uplaod GuideLines -export const UploadGuideLines = ({ uploadGuideLines, t }) => { - const formMsgFromObject = (item) => { - if (!item?.hasLink) { - return t(item?.name); - } - return ( - <> - {t(item?.name)} {t(item?.linkName)}{" "} - - ); - }; - return ( -
- {uploadGuideLines?.map((item, index) => ( -
-

- {t(index + 1)}. -

-
- {formMsgFromObject(item)} -
-
- ))} -
- ); -}; - -export const CustomIcon = (props) => { - if (!props.Icon) return null; - return ; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js deleted file mode 100644 index 5a0cdabf735..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js +++ /dev/null @@ -1,29 +0,0 @@ -import React, { memo, useCallback } from "react"; -import { useTranslation } from "react-i18next"; - -const ZoomControl = memo(({ map, t }) => { - if (!map) return
{t("LOADING_MAP")}
; - - const zoomIn = useCallback(() => { - map.zoomIn(); - }, [map]); - - const zoomOut = useCallback(() => { - map.zoomOut(); - }, [map]); - - return ( -
-
- - -
-
- ); -}); - -export default ZoomControl; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js deleted file mode 100644 index df1eb78c135..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js +++ /dev/null @@ -1,187 +0,0 @@ -import { Dropdown } from "@egovernments/digit-ui-components"; -import { Table } from "@egovernments/digit-ui-react-components"; -import { PaginationFirst, PaginationLast, PaginationNext, PaginationPrevious } from "@egovernments/digit-ui-svg-components"; -import React, { useState, useEffect, useMemo, useRef, useCallback } from "react"; -const SCROLL_OFFSET = 100; - -export const SpatialDataPropertyMapping = ({ uploadedData, resourceMapping, setResourceMapping, schema, setToast, hierarchy, close, t }) => { - // If no data is uploaded, display a message - if (!uploadedData) return
{t("NO_DATA_TO_DO_MAPPING")}
; - - const itemRefs = useRef([]); - const [expandedIndex, setExpandedIndex] = useState(null); - // State to track the render cycle count - const [renderCycle, setRenderCycle] = useState(0); - const scrollContainerRef = useRef(null); - - // Effect to reset the render cycle count whenever the expandedIndex changes - useEffect(() => { - if (expandedIndex !== null) { - setRenderCycle(0); - } - }, [expandedIndex]); - - // Effect to handle scrolling to the expanded item after the DOM has updated - useEffect(() => { - if (renderCycle < 3) { - // Increment render cycle count to ensure multiple render checks - setRenderCycle((prev) => prev + 1); - } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { - try { - const parentElement = itemRefs.current[expandedIndex]; - const childElement = itemRefs.current[expandedIndex].children[1]; - - if (parentElement) { - const scrollContainer = scrollContainerRef.current; - const parentRect = parentElement.getBoundingClientRect(); - const containerRect = scrollContainer.getBoundingClientRect(); - - // Calculate the offset from the top of the container - const offset = parentRect.top - containerRect.top; - // Scroll the container to the target position - scrollContainer.scrollTo({ - top: scrollContainer.scrollTop + offset - SCROLL_OFFSET, - behavior: "smooth", - }); - } - - if (childElement) { - // Focus the child element if it exists - childElement.focus(); - } - } catch (error) { - console.error("Error scrolling to element:", error); - } - } - }, [renderCycle, expandedIndex]); - - // Effect to observe DOM changes in the expanded item and trigger render cycle - useEffect(() => { - if (expandedIndex !== null) { - const observer = new MutationObserver(() => { - setRenderCycle((prev) => prev + 1); - }); - - if (itemRefs.current[expandedIndex]) { - observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); - } - - return () => observer.disconnect(); - } - }, [expandedIndex]); - - // State variables - const [userColumns, setUserColumns] = useState([]); - const [templateColumns, setTemplateColumns] = useState([]); - - // Fetch template columns when schema changes - useEffect(() => { - if (!schema || !schema["schema"] || !schema.schema["Properties"]) - return setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") }); - - const columns = Object.keys(schema.schema["Properties"]); - if (columns) { - const newTemplateColumns = schema && !schema.doHierarchyCheckInUploadedData ? columns : [...hierarchy, ...columns]; - setTemplateColumns(newTemplateColumns); - } - }, [schema]); - - // Update user columns when uploaded data changes - useEffect(() => { - const userUploadedColumns = new Set(); - uploadedData?.["features"]?.forEach((item) => { - Object.keys(item["properties"]).forEach((key) => userUploadedColumns.add(key)); - }); - - //field level validations - for (const item of userUploadedColumns) { - if (item.length < 2) { - setToast({ state: "error", message: t("ERROR_FIELD_LENGTH") }); - close(); - } - } - setUserColumns((preUserColumns) => [...preUserColumns, ...userUploadedColumns]); - }, [uploadedData]); - - // Dropdown component for selecting user columns - const DropDownUserColumnSelect = ({ id, index }) => { - const [selectedOption, setSelectedOption] = useState(""); - useEffect(() => { - const obj = resourceMapping.find((item) => item["mappedTo"] === id); - if (obj) setSelectedOption({ code: obj["mappedFrom"] }); - else setSelectedOption(); - }, [id, resourceMapping]); - - const handleSelectChange = (event) => { - const newValue = event.code; - setSelectedOption(event); - setResourceMapping((previous) => { - const revisedData = previous.filter((item) => !(item["mappedTo"] === id || item["mappedFrom"] === newValue)); - return [...revisedData, { mappedTo: id, mappedFrom: newValue }]; - }); - }; - - const toggleExpand = (index) => { - setExpandedIndex(index === expandedIndex ? null : index); - }; - - return ( -
{ - itemRefs.current[index] = el; - }} - onClick={() => toggleExpand(index)} - onKeyDown={() => toggleExpand(index)} - > - ({ code: item }))} - selected={selectedOption} - optionKey="code" - select={handleSelectChange} - style={{ width: "100%", backgroundColor: "rgb(0,0,0,0)" }} - showToolTip={true} - /> -
- ); - }; - - const tableColumns = useMemo( - () => [ - { - Header: t("COLUMNS_IN_TEMPLATE"), - accessor: "COLUMNS_IN_TEMPLATE", - }, - { - Header: t("COLUMNS_IN_USER_UPLOAD"), - accessor: "COLUMNS_IN_USER_UPLOAD", - Cell: ({ cell: { value }, row: { index } }) => - useMemo(() => , [value, index]), - }, - ], - [userColumns, setResourceMapping, resourceMapping, t, itemRefs] - ); - const data = useMemo(() => templateColumns.map((item) => ({ COLUMNS_IN_TEMPLATE: t(item), COLUMNS_IN_USER_UPLOAD: item })), [templateColumns]); - return ( -
- { - return { style: {} }; - }} - getHeaderProps={(cellInfo) => { - return { style: {} }; - }} - /> - - ); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js deleted file mode 100644 index 8f7fd717aba..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js +++ /dev/null @@ -1,324 +0,0 @@ -import _ from "lodash"; - -//create functions here based on module name set in mdms(eg->SearchProjectConfig) -//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] -// these functions will act as middlewares -// var Digit = window.Digit || {}; - -const businessServiceMap = { - "muster roll": "MR", -}; - -const inboxModuleNameMap = { - "muster-roll-approval": "muster-roll-service", -}; - -function filterUniqueByKey(arr, key) { - const uniqueValues = new Set(); - const result = []; - - arr.forEach((obj) => { - const value = obj[key]; - if (!uniqueValues.has(value)) { - uniqueValues.add(value); - result.push(obj); - } - }); - - return result; -} - -const epochTimeForTomorrow12 = () => { - const now = new Date(); - - // Create a new Date object for tomorrow at 12:00 PM - const tomorrowNoon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 12, 0, 0, 0); - - // Format the date as "YYYY-MM-DD" - const year = tomorrowNoon.getFullYear(); - const month = String(tomorrowNoon.getMonth() + 1).padStart(2, "0"); // Months are 0-indexed - const day = String(tomorrowNoon.getDate()).padStart(2, "0"); - - return Digit.Utils.date.convertDateToEpoch(`${year}-${month}-${day}`); -}; - -function cleanObject(obj) { - for (const key in obj) { - if (Object.hasOwn(obj, key)) { - if (Array.isArray(obj[key])) { - if (obj[key].length === 0) { - delete obj[key]; - } - } else if ( - obj[key] === undefined || - obj[key] === null || - obj[key] === false || - obj[key] === "" || // Check for empty string - (typeof obj[key] === "object" && Object.keys(obj[key]).length === 0) - ) { - delete obj[key]; - } - } - } - return obj; -} - -export const UICustomizations = { - businessServiceMap, - updatePayload: (applicationDetails, data, action, businessService) => { - if (businessService === businessServiceMap.estimate) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - estimate: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap.contract) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - contract: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["muster roll"]) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - musterRoll: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["works.purchase"]) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - const additionalFieldsToSet = { - projectId: applicationDetails.additionalDetails.projectId, - invoiceDate: applicationDetails.billDate, - invoiceNumber: applicationDetails.referenceId.split("_")?.[1], - contractNumber: applicationDetails.referenceId.split("_")?.[0], - documents: applicationDetails.additionalDetails.documents, - }; - return { - bill: { ...applicationDetails, ...additionalFieldsToSet }, - workflow, - }; - } - }, - enableModalSubmit: (businessService, action, setModalSubmit, data) => { - if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") { - setModalSubmit(data?.acceptTerms); - } - }, - enableHrmsSearch: (businessService, action) => { - if (businessService === businessServiceMap.estimate) { - return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); - } - if (businessService === businessServiceMap.contract) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - if (businessService === businessServiceMap?.["muster roll"]) { - return action.action.includes("VERIFY"); - } - if (businessService === businessServiceMap?.["works.purchase"]) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - return false; - }, - getBusinessService: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return businessServiceMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return businessServiceMap?.contract; - } else if (moduleCode?.includes("muster roll")) { - return businessServiceMap?.["muster roll"]; - } else if (moduleCode?.includes("works.purchase")) { - return businessServiceMap?.["works.purchase"]; - } else if (moduleCode?.includes("works.wages")) { - return businessServiceMap?.["works.wages"]; - } else if (moduleCode?.includes("works.supervision")) { - return businessServiceMap?.["works.supervision"]; - } else { - return businessServiceMap; - } - }, - getInboxModuleName: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return inboxModuleNameMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return inboxModuleNameMap?.contracts; - } else if (moduleCode?.includes("attendence")) { - return inboxModuleNameMap?.attendencemgmt; - } else { - return inboxModuleNameMap; - } - }, - SearchCampaign: { - preProcess: (data, additionalDetails) => { - const { campaignName = "", endDate = "", projectType = "", startDate = "" } = data?.state?.searchForm || {}; - data.body.CampaignDetails = {}; - data.body.CampaignDetails.pagination = data?.state?.tableForm; - data.body.CampaignDetails.tenantId = Digit.ULBService.getCurrentTenantId(); - // data.body.CampaignDetails.boundaryCode = boundaryCode; - data.body.CampaignDetails.createdBy = Digit.UserService.getUser().info.uuid; - data.body.CampaignDetails.campaignName = campaignName; - data.body.CampaignDetails.status = ["drafted"]; - if (startDate) { - data.body.CampaignDetails.startDate = Digit.Utils.date.convertDateToEpoch(startDate); - } else { - data.body.CampaignDetails.startDate = epochTimeForTomorrow12(); - } - if (endDate) { - data.body.CampaignDetails.endDate = Digit.Utils.date.convertDateToEpoch(endDate); - } - data.body.CampaignDetails.projectType = projectType?.[0]?.code; - - cleanObject(data.body.CampaignDetails); - - return data; - }, - populateProjectType: () => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - - return { - url: "/egov-mdms-service/v1/_search", - params: { tenantId }, - body: { - MdmsCriteria: { - tenantId, - moduleDetails: [ - { - moduleName: "HCM-PROJECT-TYPES", - masterDetails: [ - { - name: "projectTypes", - }, - ], - }, - ], - }, - }, - changeQueryName: "projectType", - config: { - enabled: true, - select: (data) => { - const dropdownData = filterUniqueByKey(data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes, "code").map((row) => { - return { - ...row, - i18nKey: Digit.Utils.locale.getTransformedLocale(`CAMPAIGN_TYPE_${row.code}`), - }; - }); - return dropdownData; - }, - }, - }; - }, - customValidationCheck: (data) => { - //checking if both to and from date are present then they should be startDate<=endDate - const { startDate, endDate } = data; - const startDateEpoch = Digit.Utils.date.convertDateToEpoch(startDate); - const endDateEpoch = Digit.Utils.date.convertDateToEpoch(endDate); - - if (startDate && endDate && startDateEpoch > endDateEpoch) { - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - } - return false; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "CAMPAIGN_DATE") { - return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.endDate)}`; - } - }, - }, - SearchMicroplan: { - preProcess: (data, additionalDetails) => { - const { name, status } = data?.state?.searchForm || {}; - - data.body.PlanConfigurationSearchCriteria = {}; - data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit; - // data.body.PlanConfigurationSearchCriteria.limit = 10 - data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset; - data.body.PlanConfigurationSearchCriteria.name = name; - data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid; - // delete data.body.PlanConfigurationSearchCriteria.pagination - data.body.PlanConfigurationSearchCriteria.status = status?.status; - cleanObject(data.body.PlanConfigurationSearchCriteria); - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "CAMPAIGN_DATE") { - return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.CampaignDetails?.endDate)}`; - } - }, - }, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js deleted file mode 100644 index c9f5af95d46..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js +++ /dev/null @@ -1,36 +0,0 @@ -export const LOCALITY = "Locality"; - -export const EXCEL = "Excel"; - -export const GEOJSON = "GeoJSON"; - -export const SHAPEFILE = "Shapefile"; - -export const commonColumn = "boundaryCode"; - -export const ACCEPT_HEADERS = { - GeoJSON: "application/geo+json", - Shapefile: "application/shapefile", - Excel: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", -}; - -// Define the colors of the gradient for choropleth mapping -export const MapChoroplethGradientColors = [ - { percent: 0, color: "#edd1cf" }, - { percent: 100, color: "#b52626" }, -]; - -export const PRIMARY_THEME_COLOR = "#C84C0E"; - -export const BOUNDARY_DATA_SHEET = "MICROPLAN_BOUNDARY_DATA_SHEET"; -export const FACILITY_DATA_SHEET = "MICROPLAN_FACILITY_DATA_SHEET"; - -export const FILE_STORE = "microplan"; - -export const SHEET_PASSWORD = "eGov_sheet_password"; - -export const SHEET_COLUMN_WIDTH = 40; - -export const SCHEMA_PROPERTIES_PREFIX = "DISPLAY"; - -export const UNPROTECT_TILL_ROW = "10000"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json deleted file mode 100644 index 768e323ef86..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "timeLineOptions": [ - { - "id": 0, - "name": "MICROPLAN_DETAILS", - "component": "MicroplanDetails", - "checkForCompleteness": true - }, - { - "id": 1, - "name": "UPLOAD_DATA", - "component": "Upload", - "checkForCompleteness": true - }, - { - "id": 2, - "name": "HYPOTHESIS", - "component": "Hypothesis", - "checkForCompleteness": true - }, - { - "id": 3, - "name": "FORMULA_CONFIGURATION", - "component": "RuleEngine", - "checkForCompleteness": true - }, - { - "id": 4, - "name": "MAPPING", - "component": "Mapping", - "checkForCompleteness": false - }, - { - "id": 5, - "name": "MICROPLAN_GENERATION", - "component": "MicroplanPreview", - "checkForCompleteness": false - } - ] -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js deleted file mode 100644 index 241f8ec64ec..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js +++ /dev/null @@ -1,193 +0,0 @@ -export const tourSteps = (t) => { - return { - microplanDetails: { - name: "microplanDetails", - run: true, - steps: [ - { - content: t("HELP_MICROPLAN_DETAILS_CAMPAIGN_DETAILS"), - target: ".microplan-campaign-detials", - disableBeacon: true, - placement: "bottom", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_MICROPLAN_DETAILS_MICROPLAN_NAME"), - target: ".microplan-name", - disableBeacon: true, - placement: "bottom", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - ], - tourActive: true, - }, - upload: { - name: "upload", - run: true, - steps: [ - { - content: t("HELP_UPLOAD_FILETYPE_OPTION_CONTAINER"), - target: ".upload-option-container", - disableBeacon: true, - placement: "top-end", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - ], - tourActive: true, - }, - hypothesis: { - name: "hypothesis", - run: true, - steps: [ - { - content: t("HELP_HYPOTHESIS_INTERACTABLE_SECTION"), - target: ".hypothesis-help", - disableBeacon: true, - placement: "right-start", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - // { - // content: - // t("HELP_RULE_ENGINE_INPUT"), - // target: ".last-container .key", - // disableBeacon: true, - // placement: "top-start", - // title: "", - // }, - // { - // content: - // t("HELP_HYPOTHESIS_DELETE_BUTTON"), - // target: ".last-containe .delete-button-help-locator", - // disableBeacon: true, - // placement: "top-start", - // title: "", - // }, - { - content: t("HELP_HYPOTHESIS_ADD_BUTTON"), - target: ".add-button-help", - disableBeacon: true, - placement: "top-start", - title: "", - disableOverlay :true, - }, - ], - tourActive: true, - }, - ruleEngine: { - name: "ruleEngine", - run: true, - steps: [ - { - content: t("HELP_RULE_ENGINE_INTERACTABLE_SECTION"), - target: ".rule-engine-help", - disableBeacon: true, - placement: "right-start", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_RULE_ENGINE_INPUT"), - target: ".user-input-section .interactable-section .select-and-input-wrapper-first .input", - disableBeacon: true, - placement: "top-end", - title: "", - disableOverlay :true, - }, - { - content: t("HELP_RULE_ENGINE_DELETE_BUTTON"), - target: ".select-and-input-wrapper-first .delete-button", - disableBeacon: true, - placement: "left-start", - title: "", - disableOverlay :true, - }, - { - content: t("HELP_RULE_ENGINE_ADD_BUTTON"), - target: ".add-button-help", - disableBeacon: true, - placement: "top-start", - title: "", - disableOverlay :true, - }, - ], - tourActive: true, - }, - mapping: { - name: "mapping", - run: true, - steps: [ - { - content: t("HELP_MAPPING_BOUNDARY_SELECTION"), - target: ".filter-by-boundary .button-primary", - disableBeacon: true, - placement: "right-end", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_MAPPING_BASE_MAP"), - target: ".base-map-selector .icon-first", - disableBeacon: true, - placement: "left-start", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_MAPPING_FILTER"), - target: ".filter-icon p", - disableBeacon: true, - placement: "left-start", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_MAPPING_VIRTUALIZATION"), - target: ".virtualization-icon p", - disableBeacon: true, - placement: "left-start", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_MAPPING_MAP_GEOMETRIES"), - target: ".map-container", - disableBeacon: true, - placement: "top-end", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - ], - tourActive: true, - }, - microplanPreview: { - name: "microplanPreview", - run: true, - steps: [ - { - content: t("HELP_MICROPLAN_DETAILS_EDIT_ROWS"), - target: ".preview-container", - disableBeacon: true, - placement: "top-end", - title: "", - disableOverlay :true, - disableScrolling: true, - }, - ], - tourActive: true, - }, - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js deleted file mode 100644 index 1241d678738..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js +++ /dev/null @@ -1,42 +0,0 @@ -import utils from "../utils"; -import useCreatePlanConfig from "./useCreatePlanConfig"; -import useSearchPlanConfig from "./useSearchPlanConfig"; -import useUpdatePlanConfig from "./useUpdatePlanConfig"; -import useSavedMicroplans from "./useSavedMicroplans"; -import useSearchCampaign from "./useSearchCampaign"; -import { useGenerateIdCampaign } from "./useGenerateIdCampaign"; -const UserService = {}; - -const microplan = { - useCreatePlanConfig, - useSearchPlanConfig, - useUpdatePlanConfig, - useSavedMicroplans, - useSearchCampaign, - useGenerateIdCampaign, -}; - -const contracts = {}; - -const Hooks = { - attendance: { - update: () => {}, - }, - microplan, - contracts, -}; - -const Utils = { - browser: { - sample: () => {}, - }, - microplan: { - ...utils, - }, -}; - -export const CustomisedHooks = { - Hooks, - UserService, - Utils, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js deleted file mode 100644 index 6afb891b15b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useMutation } from "react-query"; -import CreatePlanConfig from "../services/CreatePlanConfig"; - -const useCreatePlanConfig = () => { - return useMutation(data => CreatePlanConfig(data)) -} - -export default useCreatePlanConfig; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js deleted file mode 100644 index f315dda5ff8..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js +++ /dev/null @@ -1,26 +0,0 @@ -export const useGenerateIdCampaign = ({ type, hierarchyType, filters, campaignId, config = {} }) => { - const updatedFilters = filters?.map(({ type, ...rest }) => ({ - ...rest, - boundaryType: type, - })); - const reqCriteria = { - url: `/project-factory/v1/data/_generate`, - changeQueryName: `${type}${hierarchyType}${filters}`, - params: { - tenantId: Digit.ULBService.getCurrentTenantId(), - type: type, - forceUpdate: true, - hierarchyType: hierarchyType, - campaignId: campaignId, - }, - body: type === "boundary" ? (updatedFilters === undefined ? { Filters: null } : { Filters: { boundaries: updatedFilters } }) : {}, - config: { - ...config, - cacheTime: 0, - staleTime: 0, - }, - }; - const { data: Data, refetch, isLoading } = Digit.Hooks.useCustomAPIHook(reqCriteria); - - return { isLoading: isLoading, data: Data?.GeneratedResource?.[0]?.id, refetch }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js deleted file mode 100644 index 15e423d59e0..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js +++ /dev/null @@ -1,21 +0,0 @@ -import { useTranslation } from "react-i18next"; - -export const useNumberFormatter = (FormatMapping) => { - const { i18n } = useTranslation(); - - const formatNumber = (value, options) => { - try { - const currentLanguage = i18n.language; - const fallbackLanguage = i18n.options.fallbackLng[0]; // Get the first language in the fallback list - const locale = FormatMapping?.[currentLanguage] || FormatMapping?.[fallbackLanguage] || currentLanguage || ""; - return new Intl.NumberFormat(locale, options).format(value); - } catch (error) { - console.error("Error formatting number:", error); - return value; - } - }; - - return { formatNumber }; -}; - -export default useNumberFormatter; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js deleted file mode 100644 index 23c1259c6c4..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js +++ /dev/null @@ -1,23 +0,0 @@ -import { useQuery } from "react-query"; -import SearchSavedPlans from "../services/searchSavedPlans"; - -const useSavedMicroplans = (reqCriteria) => { - const { body, config, params, state, url } = reqCriteria; - const { isLoading, data, isFetching, refetch } = useQuery(["SAVED_MICROPLANS", url], () => SearchSavedPlans(body), { - ...config, - cacheTime: 0, - staleTime: 0, - onError: (err) => console.error("Error fetching saved microplans:", err), - }); - - return { - isLoading, - isFetching, - data, - refetch, - revalidate: () => {}, - }; -}; - -// () => SearchSavedPlans(data) -export default useSavedMicroplans; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js deleted file mode 100644 index e2644f00ca9..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useQuery } from "react-query"; -import SearchCampaignConfig from "../services/SearchCampaignConfig"; - -const useSearchCampaign = (data, config = {}) => { - return useQuery(["SEARCH_CAMPAIGN",data], () => SearchCampaignConfig(data), { ...config }); -}; - -export default useSearchCampaign; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js deleted file mode 100644 index 003fdaa4f51..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useMutation } from "react-query"; -import SearchPlanConfig from "../services/SearchPlanConfig"; - -const useSearchPlanConfig = (data, config = {}) => { - return useQuery([data?.tenantId, data?.id, data?.name, data?.executionPlanId, data?.userUuid, data?.offset, data?.limit], () => SearchPlanConfig(data), { ...config }); -}; - -export default useSearchPlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js deleted file mode 100644 index 17b16145a08..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useMutation } from "react-query"; -import UpdatePlanConfig from "../services/UpdatePlanConfig"; - -const useUpdatePlanConfig = () => { - return useMutation(data => UpdatePlanConfig(data)) -} - -export default useUpdatePlanConfig; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js deleted file mode 100644 index 03f82f59456..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js +++ /dev/null @@ -1,217 +0,0 @@ -import React from "react"; - -export const PopulationSvg = (style) => { - return ` - - - - - - - - - - - - `; -}; - -export const HelpOutlineIcon = ({ className = "", fill = "", style = {} }) => ( - - - - - - - - - - -); - -export const DefaultMapMarkerSvg = (style) => { - return ` - - - - - `; -}; - - -export const WarehouseMarker = ({ - className = "", - fill = "white", - fillBackground = "#42BBFF", - style = {}, - width = "3.125rem", - height = "3.125rem", -}) => { - return ` - - - - - - - - - - - - `; -}; - -export const Warehouse = ({ className = "", fill = "white", fillBackground = "#42BBFF", style = {}, width = "1.5rem", height = "1.5rem" }) => { - return ( - - - - - - - - - - - - ); -}; - -export const Church = ({ className = "", fill = "white", fillBackground = "#064466", style = {}, width = "1.5rem", height = "1.5rem" }) => { - return ( - - - - - - - - - - - - - ); -}; - -export const School = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "1.5rem", height = "1.5rem" }) => { - return ( - - - - - - - - - - - - - - - - - ); -}; - -export const HealthFacility = ({ className = "", fill = "white", fillBackground = "#0C9219", style = {}, width = "1.5rem", height = "1.5rem" , onClick=null}) => { - return ( - - - - - - - - - - - - ); -}; - -export const ChurchMarker = ({ className = "", fill = "white", fillBackground = "#064466", style = {}, width = "3.125rem", height = "3.125rem" }) => { - return ` - - - - - -`; -}; - -export const SchoolMarker = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "3.125rem", height = "3.125rem" }) => { - return ` - - - - - - - - - - - - - - - - -`; -}; - -export const HealthFacilityMarker = ({ - className = "", - fill = "white", - fillBackground = "#0C9219", - style = {}, - width = "3.125rem", - height = "3.125rem", -}) => { - return ` - - - - - - - - - - - -`; -}; - - - - - -export const PlusWithSurroundingCircle = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "1rem", height = "1rem" ,onClick=null }) => { - return ( - - - - ); -}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js deleted file mode 100644 index 3885795450c..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js +++ /dev/null @@ -1,288 +0,0 @@ -import React, { useState, useEffect, useCallback, Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { timeLineOptions } from "../../configs/timeLineOptions.json"; -import Upload from "../../components/Upload"; -import Hypothesis from "../../components/Hypothesis"; -import RuleEngine from "../../components/RuleEngine"; -import Mapping from "../../components/Mapping"; -import Navigator from "../../components/Nagivator"; -import { Toast } from "@egovernments/digit-ui-components"; -import MicroplanPreview from "../../components/MicroplanPreview"; -import MicroplanDetails from "../../components/MicroplanDetails"; - -export const components = { - MicroplanDetails, - Upload, - Hypothesis, - RuleEngine, - Mapping, - MicroplanPreview, -}; - -import MicroplanCreatedScreen from "../../components/MicroplanCreatedScreen"; -import { LoaderWithGap, Tutorial } from "@egovernments/digit-ui-react-components"; -import { useMyContext } from "../../utils/context"; -import { updateSessionUtils } from "../../utils/updateSessionUtils"; -import { render } from "react-dom"; - -// Main component for creating a microplan -const CreateMicroplan = () => { - // Fetching data using custom MDMS hook - const { id: campaignId = "" } = Digit.Hooks.useQueryParams(); - const { mutate: CreateMutate } = Digit.Hooks.microplan.useCreatePlanConfig(); - const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig(); - const [toRender, setToRender] = useState("navigator"); - const { t } = useTranslation(); - - // States - const [microplanData, setMicroplanData] = useState(); - const [operatorsObject, setOperatorsObject] = useState([]); - const [toast, setToast] = useState(); - const [checkForCompleteness, setCheckForCompletion] = useState([]); - const [loaderActivation, setLoaderActivation] = useState(false); - const { state } = useMyContext(); - - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - // to save microplan helper data to ssn - useEffect(() => { - if (campaignData) Digit.SessionStorage.set("microplanHelperData", { ...Digit.SessionStorage.get("microplanHelperData"), campaignData }); - }, [campaignData]); - - const campaignType = campaignData?.projectType; - - // request body for boundary hierarchy api - const reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - hierarchyType: campaignData?.hierarchyType, - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => item?.boundaryType) || {}; - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchyData } = Digit.Hooks.useCustomAPIHook(reqCriteria); - - // useEffect to initialise the data from MDMS - useEffect(() => { - let temp; - if (!state || !state.UIConfiguration) return; - const UIConfiguration = state?.UIConfiguration || {}; - if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); - if (!temp?.ruleConfigureOperators) return; - setOperatorsObject(temp.ruleConfigureOperators); - }, []); - - // useEffect to store data in session storage - useEffect(() => { - if (!microplanData) return; - Digit.SessionStorage.set("microplanData", microplanData); - }, [microplanData]); - - // useEffect to store data in session storage - useEffect(() => { - const data = Digit.SessionStorage.get("microplanData"); - if (data?.microplanStatus === "GENERATED") setToRender("success-screen"); - let statusData = {}; - let toCheckCompletenesData = []; - timeLineOptions.forEach((item) => { - statusData[item.name] = false; - if (item?.checkForCompleteness) toCheckCompletenesData.push(item.name); - }); - if (data && data?.status) { - if (Object.keys(data?.status) === 0) setMicroplanData({ ...data, status: statusData }); - else setMicroplanData({ ...data }); - } - setCheckForCompletion(toCheckCompletenesData); - }, []); - - // An addon function to pass to Navigator - const nextEventAddon = useCallback( - async (currentPage, checkDataCompletion, setCheckDataCompletion) => { - if (!microplanData) { - setCheckDataCompletion("perform-action"); - return; - } - setMicroplanData((previous) => ({ - ...previous, - status: { ...previous?.status, [currentPage?.name]: checkDataCompletion === "valid" }, - })); - - setCheckDataCompletion("false"); - let body = Digit.Utils.microplan.mapDataForApi( - microplanData, - operatorsObject, - microplanData?.microplanDetails?.name, - campaignId, - "DRAFT", - microplanData?.planConfigurationId ? "update" : "create" - ); - if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) { - setCheckDataCompletion("perform-action"); - return; - } - setLoaderActivation(true); - try { - if (!microplanData?.planConfigurationId) { - await createPlanConfiguration(body, setCheckDataCompletion, setLoaderActivation, state); - } else if (microplanData?.planConfigurationId) { - await updatePlanConfiguration(body, setCheckDataCompletion, setLoaderActivation, state); - } - } catch (error) { - console.error("Failed to create/update plan configuration:", error); - } - }, - [microplanData, UpdateMutate, CreateMutate] - ); - - const createPlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation, state) => { - await CreateMutate(body, { - onSuccess: async (data) => { - const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); - const additionalProps = { - hierarchyData: hierarchyData, - t, - campaignType, - campaignData, - readMeSheetName: readMeConstant ? readMeConstant.value : undefined, - }; - const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps); - if (computedSession) { - computedSession.microplanStatus = "DRAFT"; - setMicroplanData(computedSession); - } else { - console.error("Failed to compute session data."); - } - setLoaderActivation(false); - setCheckDataCompletion("perform-action"); - }, - onError: (error, variables) => { - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - transitionTime: 10000, - }); - setTimeout(() => { - setLoaderActivation(false); - setCheckDataCompletion("false"); - }, 2000); - }, - }); - }; - - const updatePlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation, state) => { - body.PlanConfiguration["id"] = microplanData?.planConfigurationId; - body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; - await UpdateMutate(body, { - onSuccess: async (data) => { - const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); - const additionalProps = { - hierarchyData: hierarchyData, - t, - campaignType, - campaignData, - readMeSheetName: readMeConstant ? readMeConstant.value : undefined, - }; - const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps); - if (computedSession) { - computedSession.microplanStatus = "DRAFT"; - setMicroplanData(computedSession); - } else { - console.error("Failed to compute session data."); - } - setLoaderActivation(false); - setCheckDataCompletion("perform-action"); - }, - onError: (error, variables) => { - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - transitionTime: 10000, - }); - setTimeout(() => { - setLoaderActivation(false); - setCheckDataCompletion("false"); - }, 2000); - }, - }); - }; - - const setCurrentPageExternally = useCallback( - (props) => { - switch (props.method) { - case "set": { - let currentPage; - const data = Digit.SessionStorage.get("microplanData"); - if (data?.currentPage) currentPage = data.currentPage; - if (currentPage && props?.setCurrentPage && timeLineOptions.find((item) => item.id === currentPage?.id)) { - props.setCurrentPage(currentPage); - return true; - } - break; - } - case "save": { - if (props.currentPage) { - setMicroplanData((previous) => ({ ...previous, currentPage: props.currentPage })); - } - break; - } - } - }, - [microplanData, setMicroplanData, Navigator] - ); - - const completeNavigation = useCallback(() => { - setToRender("success-screen"); - }, [setToRender]); - - return ( - <> -
- {toRender === "navigator" && ( - - )} - {toRender === "success-screen" && } -
- {toast && ( - setToast(undefined)} - /> - )} - {loaderActivation && } - - ); -}; - -export default CreateMicroplan; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js deleted file mode 100644 index 7534c1b2af1..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js +++ /dev/null @@ -1,54 +0,0 @@ -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; -import { ArrowForward } from "@egovernments/digit-ui-svg-components"; -import { Button } from "@egovernments/digit-ui-react-components"; -import { useHistory } from "react-router-dom"; -import { ActionBar } from "@egovernments/digit-ui-components"; - -const Guidelines = ({ path }) => { - const { t } = useTranslation(); - const history = useHistory() - // Keeping inline style for now because design for this screen is not given yet - const { id = "" } = Digit.Hooks.useQueryParams(); - const onNextClick = ()=>{ - history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${id}`); - } - return ( - <> - -
- {t("CREATE_MICROPLAN_GUIDELINES")} -
- - {/* Action bar */} - - {/* Next/Submit button */} - - - - ); -}; - -export default Guidelines; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js deleted file mode 100644 index bbb0aef7628..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js +++ /dev/null @@ -1,200 +0,0 @@ -import React, { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { Header, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components"; -import { useHistory } from "react-router-dom"; -import { updateSessionUtils } from "../../utils/updateSessionUtils"; -import { useMyContext } from "../../utils/context"; - -const configs = { - label: "SAVED_MICROPLANS", - type: "search", - apiDetails: { - serviceName: "/plan-service/config/_search", - requestParam: {}, - requestBody: {}, - minParametersForSearchForm: 0, - masterName: "commonUiConfig", - moduleName: "SearchMicroplan", - tableFormJsonPath: "requestBody.PlanConfigurationSearchCriteria.pagination", - searchFormJsonPath: "requestBody.PlanConfigurationSearchCriteria", - }, - sections: { - search: { - uiConfig: { - type: "search", - typeMobile: "filter", - headerLabel: "SAVED_MICROPLANS", - headerStyle: null, - primaryLabel: "ES_COMMON_SEARCH", - secondaryLabel: "ES_COMMON_CLEAR_SEARCH", - minReqFields: 0, - // "showFormInstruction": "TQM_SEARCH_HINT", - defaultValues: { - name: "", - status: "", - }, - fields: [ - { - label: "MICROPLAN_NAME", - type: "text", - isMandatory: false, - disable: false, - populators: { - name: "name", - style: { - marginBottom: "0px", - }, - }, - }, - { - label: "MICROPLAN_STATUS", - type: "dropdown", - isMandatory: false, - disable: false, - populators: { - name: "status", - optionsKey: "status", - optionsCustomStyle: { - top: "2.3rem", - }, - mdmsConfig: { - masterName: "MicroplanStatus", - moduleName: "hcm-microplanning", - localePrefix: "MICROPLAN_STATUS", - }, - }, - }, - ], - }, - label: "", - children: {}, - show: true, - // "labelMobile": "TQM_INBOX_SEARCH" - }, - searchResult: { - uiConfig: { - columns: [ - { - label: "MICROPLAN_NAME", - jsonPath: "name", - }, - { - label: "MICROPLAN_STATUS", - jsonPath: "status", - prefix: "MICROPLAN_STATUS_COLUMN_", - translate: true, - }, - { - label: "CAMPAIGNS_ASSIGNED", - jsonPath: "CampaignDetails.campaignName", - }, - { - label: "CAMPAIGN_DATE", - jsonPath: "CampaignDetails.startDate", - additionalCustomization: true, - }, - ], - showActionBarMobileCard: true, - actionButtonLabelMobileCard: "TQM_VIEW_RESULTS", - enableGlobalSearch: false, - enableColumnSort: true, - resultsJsonPath: "PlanConfiguration", - tableClassName: "table pqm-table", - noColumnBorder: true, - rowClassName: "table-row-mdms table-row-mdms-hover", - }, - children: {}, - show: true, - }, - }, - additionalSections: {}, - persistFormData: true, - showAsRemovableTagsInMobile: false, - customHookName: "microplan.useSavedMicroplans", -}; - -const SavedMicroplans = () => { - const [showLoader, setShowLoader] = useState(false); - const { state } = useMyContext(); - const history = useHistory(); - const { t } = useTranslation(); - - const fetchHierarchyData = async (hierarchyType) => { - const response = await Digit.CustomService.getResponse({ - url: "/boundary-service/boundary-hierarchy-definition/_search", - useCache: false, - method: "POST", - userService: false, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - hierarchyType, - }, - }, - }); - if (response?.BoundaryHierarchy?.length) { - return response.BoundaryHierarchy[0].boundaryHierarchy.map((item) => item.boundaryType); - } - console.error("Invalid response structure"); - }; - - const computeAdditionalProps = (row, state, t, hierarchyData) => { - const campaignDetails = row?.original?.CampaignDetails; - const readMeSheetName = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value; - return { - hierarchyData, - t, - campaignType: campaignDetails?.projectType, - campaignData: campaignDetails, - readMeSheetName, - }; - }; - - const onClickRow = (row) => { - const handleClick = async () => { - setShowLoader(true); - try { - const campaignType = row?.original?.CampaignDetails?.projectType; - const hierarchyData = await fetchHierarchyData(row?.original?.CampaignDetails?.hierarchyType); - const additionalProps = computeAdditionalProps(row, state, t, hierarchyData); - - // Compute the session object based on the row?.original data and then re-route - const computedSession = await updateSessionUtils.computeSessionObject(row.original, state, additionalProps); - Digit.SessionStorage.set("microplanData", computedSession); - - setShowLoader(false); - history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.executionPlanId}`); - } catch (error) { - console.error(`Failed to process the request: ${error.message}`); - setShowLoader(false); - } - }; - - handleClick(); - }; - - const savedMircoplanSession = Digit.Hooks.useSessionStorage("SAVED_MICROPLAN_SESSION", {}); - - if (showLoader) { - return ; - } - - return ( - -
{t(configs?.label)}
-
- -
-
- ); -}; - -export default SavedMicroplans; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js deleted file mode 100644 index 8f2131eefdd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js +++ /dev/null @@ -1,226 +0,0 @@ -import React, { useEffect, useMemo } from "react"; -import { useTranslation } from "react-i18next"; -import { Header, InboxSearchComposer, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components"; -import { useHistory, useParams } from "react-router-dom"; - -const configs = { - label: "SELECT_CAMPAIGN", - type: "search", - apiDetails: { - serviceName: "/project-factory/v1/project-type/search", - requestParam: {}, - requestBody: {}, - minParametersForSearchForm: 0, - masterName: "commonUiConfig", - moduleName: "SearchCampaign", - tableFormJsonPath: "requestBody.CampaignDetails.pagination", - searchFormJsonPath: "requestBody.CampaignDetails", - }, - sections: { - search: { - uiConfig: { - type: "search", - // typeMobile: "filter", - headerLabel: "SELECT_CAMPAIGN", - headerStyle: null, - primaryLabel: "ES_COMMON_SEARCH", - secondaryLabel: "ES_COMMON_CLEAR_SEARCH", - minReqFields: 1, - // "showFormInstruction": "TQM_SEARCH_HINT", - defaultValues: { - campaignName: "", - projectType: "", - startDate: "", - endDate: "", - boundaryCode: "", - }, - fields: [ - { - label: "CAMPAIGN_NAME", - type: "text", - isMandatory: false, - disable: false, - populators: { - name: "campaignName", - style: { - marginBottom: "0px", - }, - error: "ERR_MIN_LENGTH_CAMPAIGN_NAME", - validationErrorStyles: { - marginTop: "0.3rem", - }, - validation: { - minLength: 2, - }, - }, - }, - // { - // label: "CAMPAIGN_TYPE", - // type: "dropdown", - // isMandatory: false, - // disable: false, - // populators: { - // name: "projectType", - // optionsKey: "name", - // optionsCustomStyle: { - // top: "2.3rem", - // }, - // mdmsConfig: { - // masterName: "projectTypes", - // moduleName: "HCM-PROJECT-TYPES", - // localePrefix: "CAMPAIGN_TYPE", - // }, - // }, - // }, - { - label: "CAMPAIGN_TYPE", - type: "apidropdown", - isMandatory: false, - disable: false, - populators: { - name: "projectType", - optionsKey: "i18nKey", - optionsCustomStyle: { - top: "2.3rem", - }, - allowMultiSelect: false, - masterName: "commonUiConfig", - moduleName: "SearchCampaign", - customfn: "populateProjectType", - }, - }, - { - label: "CAMPAIGN_START_DATE", - type: "date", - isMandatory: false, - key: "startDate", - disable: false, - preProcess: { - updateDependent: ["populators.max"], - }, - populators: { - name: "startDate", - style: { - marginBottom: "0px", - }, - error: "DATE_VALIDATION_MSG", - }, - }, - { - label: "CAMPAIGN_END_DATE", - type: "date", - isMandatory: false, - disable: false, - key: "endDate", - preProcess: { - updateDependent: ["populators.max"], - }, - populators: { - name: "endDate", - error: "DATE_VALIDATION_MSG", - min: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString().slice(0, 10), - style: { - marginBottom: "0px", - }, - }, - }, - // { - // label: "CAMPAIGN_BOUNDARY", - // type: "text", - // isMandatory: false, - // disable: false, - // populators: { - // name: "boundaryCode", - // style: { - // marginBottom: "0px", - // }, - // }, - // }, - ], - }, - label: "", - children: {}, - show: true, - // "labelMobile": "TQM_INBOX_SEARCH" - }, - searchResult: { - uiConfig: { - columns: [ - { - label: "CAMPAIGN_NAME", - jsonPath: "campaignName", - // "additionalCustomization": true - }, - { - label: "CAMPAIGN_TYPE", - jsonPath: "projectType", - // "additionalCustomization": false, - prefix: "CAMPAIGN_TYPE_", - translate: true, - }, - { - label: "CAMPAIGN_BOUNDARY_CAMP", - jsonPath: "boundaryCode", - // "additionalCustomization": false, - prefix: "CAMPAIGN_BOUNDARY_", - translate: true, - }, - { - label: "CAMPAIGN_BENEFICIARY_TYPE", - jsonPath: "additionalDetails.beneficiaryType", - prefix: "CAMPAIGN_BENEFICIARY_TYPE_", - translate: true, - }, - { - label: "CAMPAIGN_DATE", - jsonPath: "startDate", - additionalCustomization: true, - }, - ], - showActionBarMobileCard: true, - actionButtonLabelMobileCard: "TQM_VIEW_RESULTS", - enableGlobalSearch: false, - enableColumnSort: true, - resultsJsonPath: "CampaignDetails", - tableClassName: "table pqm-table", - rowClassName: "table-row-mdms table-row-mdms-hover", - noColumnBorder: true, - }, - children: {}, - show: true, - }, - }, - additionalSections: {}, - persistFormData: true, - showAsRemovableTagsInMobile: false, -}; -const SelectCampaign = () => { - const { t } = useTranslation(); - const history = useHistory(); - - const onClickRow = (row) => { - // history.push(`/${window.contextPath}/employee/microplanning/help-guidelines?id=${row?.original?.id}`); - history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.id}`); - }; - - const SelectCampaignSession = Digit.Hooks.useSessionStorage("SELECT_CAMPAIGN_SESSION", {}); - - return ( - -
{t(configs?.label)}
-
- -
-
- ); -}; - -export default SelectCampaign; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js deleted file mode 100644 index 6f58779637a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js +++ /dev/null @@ -1,128 +0,0 @@ -import React, { useEffect } from "react"; -import { Switch, useLocation } from "react-router-dom"; -import { useTranslation } from "react-i18next"; -import { PrivateRoute, AppContainer, BreadCrumb, Loader } from "@egovernments/digit-ui-react-components"; -import MicroplanningHeader from "../../components/MicroplanningHeader"; -import Guidelines from "./Guidelines"; -import CreateMicroplan from "./CreateMicroplan"; -import SavedMicroplans from "./SavedMicroplans"; -import SelectCampaign from "./SelectCampaign"; -import { useMyContext } from "../../utils/context"; - -const MicroplanningBreadCrumb = ({ location, defaultPath }) => { - const { t } = useTranslation(); - const pathVar = location.pathname.replace(`${defaultPath}/`, "").split("?")?.[0]; - const { masterName, moduleName, uniqueIdentifier } = Digit.Hooks.useQueryParams(); - - const crumbs = [ - { - path: `/${window?.contextPath}/employee`, - content: t("Home"), - show: true, - }, - // { - // content: t(`UPLOAD`) , - // show: pathVar.includes("upload")?true: false, - // }, - // { - // content: t(`HYPOTHESIS`) , - // show: pathVar.includes("hypothesis")?true: false, - // }, - // { - // content: t(`RULE_ENGINE`) , - // show: pathVar.includes("rule-engine")?true: false, - // }, - { - content: t(`CREATE_MICROPLAN`), - show: pathVar.includes("create-microplan"), - }, - { - content: t(`SAVED_MICROPLANS_TEXT`), - show: pathVar.includes("saved-microplan"), - }, - { - content: t(`CREATE_MICROPLAN`), - show: pathVar.includes("select-campaign"), - }, - ]; - return ; -}; - -const App = ({ path }) => { - const { dispatch } = useMyContext(); - - const location = useLocation(); - const MDMSCreateSession = Digit.Hooks.useSessionStorage("MDMS_add", {}); - const [sessionFormData, setSessionFormData, clearSessionFormData] = MDMSCreateSession; - - const MDMSViewSession = Digit.Hooks.useSessionStorage("MDMS_view", {}); - const [sessionFormDataView, setSessionFormDataView, clearSessionFormDataView] = MDMSViewSession; - - const { isLoading: isLoadingMdmsBaseData, data } = Digit.Hooks.useCustomMDMS( - Digit.ULBService.getCurrentTenantId(), - "hcm-microplanning", - [ - { name: "UploadConfiguration" }, - { name: "UIConfiguration" }, - { name: "Schemas" }, - { name: "RuleConfigureOutput" }, - { name: "Resources" }, - { name: "HypothesisAssumptions" }, - { name: "BaseMapLayers" }, - { name: "MicroplanPreviewAggregates" }, - { name: "AutoFilledRuleConfigurations" }, - { name: "MapFilters" }, - { name: "HierarchyConfigurations" }, - { name: "NumberFormatMappingForTranslation" }, - { name: "UploadGuidelines" }, - { name: "ReadMeData" }, - { name: "CommonConstants" }, - ], - { - select: (data) => { - dispatch({ - type: "SETINITDATA", - state: { - ...data?.["hcm-microplanning"], - }, - }); - }, - } - ); - - //destroying session - useEffect(() => { - const pathVar = location.pathname.replace(`${path}/`, "").split("?")?.[0]; - Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan"], "microplanData"); - Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan"], "microplanHelperData"); - Digit.Utils.microplan.destroySessionHelper(pathVar, ["select-campaign"], "SELECT_CAMPAIGN_SESSION"); - Digit.Utils.microplan.destroySessionHelper(pathVar, ["saved-microplans"], "SAVED_MICROPLAN_SESSION"); - }, [location]); - - if (isLoadingMdmsBaseData) { - return ; - } - - return ( - -
- - -
- - - {/* } /> - } /> - } /> */} - } /> - - } /> - } /> - } /> - - -
- ); -}; - -export default App; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js deleted file mode 100644 index cabc9b67b56..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js +++ /dev/null @@ -1,19 +0,0 @@ -const CreatePlanConfig = async (body) => { - try { - const response = await Digit.CustomService.getResponse({ - url: "/plan-service/config/_create", - useCache: false, - method: "POST", - userService: true, - body, - }); - return response; - } catch (error) { - if (error?.response?.data?.Errors) { - throw new Error(error.response.data.Errors[0].message); - } - throw new Error("An unknown error occurred"); - } -}; - -export default CreatePlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js deleted file mode 100644 index 83d4fb5fc72..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js +++ /dev/null @@ -1,181 +0,0 @@ -import _ from "lodash"; - -const createProjectsArray = (t, project, searchParams, headerLocale) => { - let totalProjects = { - searchedProject: {}, - subProjects: [], - }; - let basicDetails = {}; - let totalProjectsLength = project.length; - // for(let projectIndex = 0; projectIndex < totalProjectsLength; projectIndex++) { - let currentProject = project[0]; - const headerDetails = { - title: " ", - asSectionHeader: true, - values: [ - { title: "WORKS_PROJECT_ID", value: currentProject?.projectNumber || "NA" }, - { title: "ES_COMMON_PROPOSAL_DATE", value: Digit.Utils.pt.convertEpochToDate(currentProject?.additionalDetails?.dateOfProposal) || "NA" }, - { title: "WORKS_PROJECT_NAME", value: currentProject?.name || "NA" }, - { title: "PROJECT_PROJECT_DESC", value: currentProject?.description || "NA" }, - ], - }; - - const projectDetails = { - title: "WORKS_PROJECT_DETAILS", - asSectionHeader: true, - values: [ - { title: "PROJECT_LOR", value: currentProject?.referenceID || "NA" }, - { - title: "WORKS_PROJECT_TYPE", - value: currentProject?.projectType ? t(`COMMON_MASTERS_${Digit.Utils.locale.getTransformedLocale(currentProject?.projectType)}`) : "NA", - }, - { - title: "PROJECT_TARGET_DEMOGRAPHY", - value: currentProject?.additionalDetails?.targetDemography - ? t(`COMMON_MASTERS_${currentProject?.additionalDetails?.targetDemography}`) - : "NA", - }, - { - title: "PROJECT_ESTIMATED_COST", - value: currentProject?.additionalDetails?.estimatedCostInRs - ? `₹ ${Digit.Utils.dss.formatterWithoutRound(currentProject?.additionalDetails?.estimatedCostInRs, "number")}` - : "NA", - }, - ], - }; - - const locationDetails = { - title: "WORKS_LOCATION_DETAILS", - asSectionHeader: true, - values: [ - { - title: "WORKS_GEO_LOCATION", - value: - currentProject?.address?.latitude || currentProject?.address?.longitude - ? `${currentProject?.address?.latitude}, ${currentProject?.address?.longitude}` - : "NA", - }, - { - title: "WORKS_CITY", - value: currentProject?.address?.city ? t(`TENANT_TENANTS_${Digit.Utils.locale.getTransformedLocale(currentProject?.address?.city)}`) : "NA", - }, //will check with Backend - { title: "WORKS_WARD", value: currentProject?.address?.boundary ? t(`${headerLocale}_ADMIN_${currentProject?.address?.boundary}`) : "NA" }, ///backend to update this - { - title: "WORKS_LOCALITY", - value: currentProject?.additionalDetails?.locality ? t(`${headerLocale}_ADMIN_${currentProject?.additionalDetails?.locality}`) : "NA", - }, - ], - }; - - // const financialDetails = { - // title: "WORKS_FINANCIAL_DETAILS", - // asSectionHeader: false, - // values: [ - // { title: "WORKS_HEAD_OF_ACCOUNTS", value: currentProject?.additionalDetails?.fund ? t(`COMMON_MASTERS_FUND_${currentProject?.additionalDetails?.fund}`) : "NA" }, - // ], - // }; - - let documentDetails = { - title: "", - asSectionHeader: true, - additionalDetails: { - documents: [ - { - title: "WORKS_RELEVANT_DOCUMENTS", - BS: "Works", - values: currentProject?.documents?.map((document) => { - if (document?.status !== "INACTIVE") { - return { - title: document?.documentType === "OTHERS" ? document?.additionalDetails?.otherCategoryName : t(`PROJECT_${document?.documentType}`), - documentType: document?.documentType, - documentUid: document?.fileStore, - fileStoreId: document?.fileStore, - }; - } - return {}; - }), - }, - ], - }, - }; - - //filter any empty object - documentDetails.additionalDetails.documents[0].values = documentDetails?.additionalDetails?.documents?.[0]?.values?.filter((value) => { - if (value?.title) { - return value; - } - }); - - // if(currentProject?.projectNumber === searchParams?.Projects?.[0]?.projectNumber) { - basicDetails = { - projectID: currentProject?.projectNumber, - projectProposalDate: Digit.Utils.pt.convertEpochToDate(currentProject?.additionalDetails?.dateOfProposal) || "NA", - projectName: currentProject?.name || "NA", - projectDesc: currentProject?.description || "NA", - projectHasSubProject: totalProjectsLength > 1 ? "COMMON_YES" : "COMMON_NO", - projectParentProjectID: currentProject?.ancestors?.[0]?.projectNumber || "NA", - uuid: currentProject?.id, - address: currentProject?.address, - ward: currentProject?.address?.boundary, - locality: currentProject?.additionalDetails?.locality, - }; - totalProjects.searchedProject = { - basicDetails, - headerDetails, - projectDetails, - locationDetails, - documentDetails, - }; - // } - // } - return totalProjects; -}; - -export const Search = { - viewProjectDetailsScreen: async ( - t, - tenantId, - searchParams, - filters = { limit: 10, offset: 0, includeAncestors: true, includeDescendants: true }, - headerLocale - ) => { - const response = await Digit.WorksService?.searchProject(tenantId, searchParams, filters); - - let projectDetails = { - searchedProject: { - basicDetails: {}, - details: { - projectDetails: [], - }, - }, - }; - - if (response?.Project) { - let projects = createProjectsArray(t, response?.Project, searchParams, headerLocale); - - //searched Project details - projectDetails.searchedProject["basicDetails"] = projects?.searchedProject?.basicDetails; - projectDetails.searchedProject["details"]["projectDetails"] = { - applicationDetails: [ - projects?.searchedProject?.headerDetails, - projects?.searchedProject?.projectDetails, - projects?.searchedProject?.locationDetails, - projects?.searchedProject?.documentDetails, - ], - }; //rest categories will come here - } - - return { - projectDetails: response?.Project ? projectDetails : [], - response: response?.Project, - processInstancesDetails: [], - workflowDetails: [], - applicationData: {}, - isNoDataFound: response?.Project?.length === 0, - }; - }, - searchEstimate: async (tenantId, filters) => { - const response = await Digit.WorksService?.estimateSearch({ tenantId, filters }); - return response?.estimates; - }, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js deleted file mode 100644 index bb6a9f26916..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js +++ /dev/null @@ -1,22 +0,0 @@ -const SearchCampaignConfig = async (body) => { - try { - const response = await Digit.CustomService.getResponse({ - url: "/project-factory/v1/project-type/search", - useCache: false, - method: "POST", - userService: false, - body, - }); - if (response?.CampaignDetails?.length === 0) { - throw new Error("Campaign not found with the given id"); - } - return response?.CampaignDetails?.[0]; - } catch (error) { - if (error?.response?.data?.Errors) { - throw new Error(error.response.data.Errors[0].message); - } - throw new Error("An unknown error occurred"); - } -}; - -export default SearchCampaignConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js deleted file mode 100644 index 1fe11f206a7..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js +++ /dev/null @@ -1,19 +0,0 @@ -const SearchPlanConfig = async (body) => { - try { - const response = await Digit.CustomService.getResponse({ - url: "/plan-service/config/_search", - useCache: false, - method: "POST", - userService: true, - body, - }); - return response; - } catch (error) { - if (error?.response?.data?.Errors) { - throw new Error(error.response.data.Errors[0].message); - } - throw new Error("An unknown error occurred"); - } -}; - -export default SearchPlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js deleted file mode 100644 index d1623cbd167..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js +++ /dev/null @@ -1,18 +0,0 @@ -const UpdatePlanConfig = async (body) => { - try { - const response = await Digit.CustomService.getResponse({ - url: "/plan-service/config/_update", - useCache: false, - method: "POST", - userService: true, - body, - }); - return response; - } catch (error) { - if (error?.response?.data?.Errors) { - throw new Error(error.response.data.Errors[0].message); - } - throw new Error("An unknown error occurred"); - } -}; -export default UpdatePlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js deleted file mode 100644 index ba4342526a8..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js +++ /dev/null @@ -1,67 +0,0 @@ -function mergeArrays(array1, key1, array2, key2) { - const mergedArray = []; - - // Create a map of values from array2 using key2 - const map = new Map(); - array2.forEach((item) => { - map.set(item[key2], item); - }); - - // Iterate over array1 and merge with matching items from array2 - array1.forEach((item) => { - const matchingItem = map.get(item[key1]); - if (matchingItem) { - // Merge properties from both items and append to 'CampaignDetails' - const mergedItem = { ...item, CampaignDetails: { ...matchingItem } }; - mergedArray.push(mergedItem); - } else { - // No matching item found in array2, add array1 item with empty 'CampaignDetails' - const mergedItem = { ...item, CampaignDetails: {} }; - mergedArray.push(mergedItem); - } - }); - return mergedArray; -} - -const SearchSavedPlans = async (body) => { - try { - //here get response from both apis and process data and return - const responsePlan = await Digit.CustomService.getResponse({ - url: "/plan-service/config/_search", - useCache: false, - method: "POST", - userService: false, - body, - }); - - const { PlanConfiguration } = responsePlan; - if (!PlanConfiguration || PlanConfiguration.length === 0) return []; - - const executionPlanIds = PlanConfiguration?.map((row) => row?.executionPlanId)?.filter((item) => item); - const CampaignDetails = { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: executionPlanIds, - }; - - const responseCampaign = await Digit.CustomService.getResponse({ - url: "/project-factory/v1/project-type/search", - useCache: false, - method: "POST", - userService: false, - body: { - CampaignDetails, - }, - }); - const finalResult = { - PlanConfiguration: mergeArrays(responsePlan?.PlanConfiguration, "executionPlanId", responseCampaign?.CampaignDetails, "id"), - }; - return finalResult; - } catch (error) { - if (error?.response?.data?.Errors) { - throw new Error(error.response.data.Errors[0].message); - } - throw new Error("An unknown error occurred"); - } -}; - -export default SearchSavedPlans; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js deleted file mode 100644 index 5e6c18f699e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js +++ /dev/null @@ -1,31 +0,0 @@ -import React,{useContext,createContext,useReducer} from "react" - -const MyContext = createContext() -const initialState = { - -} - -const reducer = (state=initialState,action) => { - switch (action.type) { - case "SETINITDATA": - return {...state,...action.state} - default: - return state; - } -} - -export const useMyContext = () => { - - return useContext(MyContext) -} - -export const ProviderContext = ({children}) => { - - const [state,dispatch] = useReducer(reducer,initialState) - - return ( - - {children} - - ) -} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js deleted file mode 100644 index a3f79c2358e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js +++ /dev/null @@ -1,485 +0,0 @@ -import { BOUNDARY_DATA_SHEET, FACILITY_DATA_SHEET, SCHEMA_PROPERTIES_PREFIX, commonColumn } from "../configs/constants"; - -export const fetchBoundaryData = async (tenantId, hierarchyType, codes) => { - // request for boundary relation api - const reqCriteria = { - url: "/boundary-service/boundary-relationships/_search", - params: { tenantId, hierarchyType, codes, includeChildren: true }, - body: {}, - }; - let response; - try { - response = (await Digit.CustomService.getResponse(reqCriteria))?.TenantBoundary?.[0]?.boundary || {}; - } catch (error) { - console.error("Error in fetching boundary Data: ", error.message); - } - return response; -}; - -export const getFacilities = async (params, body) => { - // request for boundary relation api - const reqCriteria = { - url: "/facility/v1/_search", - params: params, - body: body, - }; - let response; - try { - response = (await Digit.CustomService.getResponse(reqCriteria))?.Facilities || {}; - } catch (error) { - if (error.response) { - throw new Error(`Failed to fetch facility data: ${error.response.data.message}`); - } - if (error.request) { - // Network error - throw new Error("Network error while fetching facility data"); - } - // Other errors - throw new Error(`Error while fetching facility data: ${error.message}`); - } - return response; -}; - -// export const fetchColumnsFromMdms = (schema)=>{ -// return -// } - -/** - * - * @param {*} xlsxData - * @param {*} boundaryData - * @returns xlsxData with boundary data added - */ -export const addBoundaryData = (xlsxData, boundaryData, hierarchyType) => { - // Return the original data if there is no boundary data to add - if (!boundaryData) return xlsxData; - - // Initialize the array to hold new data - let newXlsxData = []; - - // Recursive function to convert boundary data into sheet format - const convertBoundaryDataToSheets = (boundaryData, currentBoundaryPredecessor = [], hierarchyAccumulator = [], dataAccumulator = []) => { - // Return if boundary data is not valid or not an array - if (!boundaryData || !Array.isArray(boundaryData)) return; - - // Clone the current boundary predecessor to avoid modifying the original data - const rowData = [...currentBoundaryPredecessor]; - // Clone the data accumulator to preserve the accumulated data - let tempDataAccumulator = [...dataAccumulator]; - // Use a set to accumulate unique hierarchy levels - let tempHierarchyAccumulator = new Set(hierarchyAccumulator); - - // Iterate over each item in the boundary data array - for (const item of boundaryData) { - if (item?.code) { - // Create a new row with the current item's code - const tempRow = [...rowData, item?.code]; - let response; - // Add the current item's boundary type to the hierarchy - tempHierarchyAccumulator.add(item.boundaryType); - - // If the current item has children, recursively process them - if (item.children) - response = convertBoundaryDataToSheets(item.children, tempRow, tempHierarchyAccumulator, [...tempDataAccumulator, tempRow]); - - // Update the accumulators with the response from the recursive call - if (response) { - tempDataAccumulator = response.tempDataAccumulator; - tempHierarchyAccumulator = response.tempHierarchyAccumulator; - } - } - } - - // Return the accumulated data and hierarchy - return { tempDataAccumulator, tempHierarchyAccumulator }; - }; - - // Convert the boundary data into sheet format and extract the sorted data and hierarchy - let { tempDataAccumulator: sortedBoundaryDataForXlsxSheet, tempHierarchyAccumulator: hierarchy } = convertBoundaryDataToSheets(boundaryData); - - // Add the hierarchy as the first row of the sheet - hierarchy = [...hierarchy].map((item) => `${hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`); - sortedBoundaryDataForXlsxSheet = [[...hierarchy], ...sortedBoundaryDataForXlsxSheet]; - - // Determine the maximum row length to ensure all rows have the same length - const topIndex = Math.max(...sortedBoundaryDataForXlsxSheet.map((row) => row.length)) - 1; - - // Ensure all rows are of the same length by filling them with empty strings - sortedBoundaryDataForXlsxSheet = sortedBoundaryDataForXlsxSheet.map((item, index) => { - let newItem = item; - if (index !== 0) { - if (!newItem) { - newItem = []; - } - const itemLength = newItem.length; - while (newItem.length <= topIndex) { - newItem.push(""); - } - newItem.push(newItem[itemLength - 1]); - } else { - newItem.push(commonColumn); - } - - return newItem; - }); - - // Add the new sheet data to the original data - newXlsxData = [...xlsxData, ...newXlsxData, { sheetName: BOUNDARY_DATA_SHEET, data: sortedBoundaryDataForXlsxSheet }]; - - // Return the updated data - return newXlsxData; -}; - -const fillDataWithBlanks = (data, tillRow) => { - while (data.length < tillRow) { - data.push([]); - } - - const maxLength = Math.max(...data.map((row) => row.length)); - return data.map((row) => [...row, ...new Array(maxLength - row.length).fill("")]); -}; -const generateLocalisationKeyForSchemaProperties = (code) => { - if (!code) return code; - return `${SCHEMA_PROPERTIES_PREFIX}_${code}`; -}; -/** - * - * @param {array} xlsxData , xlsx data - * @param {object} schema , schema to refer to - * @returns {Array of Object} , xlsxData with schema data added - * - * adds schema data to sheets - */ -const addSchemaData = (xlsxData, schema, extraColumnsToAdd) => { - if (!schema) return xlsxData; - let columnSchema = schema.schema?.Properties || {}; - const newXlsxData = []; - const columnList = [[], [], [], []]; // Initialize columnList with four empty arrays - - for (const [key, value] of Object.entries(columnSchema)) { - if (key === commonColumn) continue; - - columnList[0].push(generateLocalisationKeyForSchemaProperties(key)); // Add key to the first array - - // columnList[1].push(value.type || ""); // Add type to the second array - - // columnList[2].push(value.isRequired ? "MANDATORY" : "OPTIONAL"); // Add requirement status to the third array - - // columnList[3].push(value.pattern || ""); // Add pattern to the fourth array - } - - if (extraColumnsToAdd) columnList[0].push(...extraColumnsToAdd); - - for (let { sheetName, data } of xlsxData) { - data = fillDataWithBlanks(data, 4); - columnList.forEach((item, index) => { - // Append the new items to the row - if (data[index]) { - data[index] = [...data[index], ...item]; - } else { - data[index] = [...item]; - } - }); - - newXlsxData.push({ sheetName, data }); - } - - return newXlsxData; -}; - -/** - * - * @param {Array of Object} xlsxData - * @param {string} hierarchyLevelName - */ -const devideXlsxDataHierarchyLevelWise = (xlsxData, hierarchyLevelName) => { - if (!hierarchyLevelName) return xlsxData; // Return original data if no hierarchy level name - - const result = []; // Initialize result array - - // Iterate over each sheet in the xlsxData - for (const sheet of xlsxData) { - const sheetData = sheet.data; - const hierarchyLevelIndex = sheetData[0].indexOf(hierarchyLevelName); - - // If hierarchy level name not found, skip this sheet - if (hierarchyLevelIndex === -1) { - result.push(sheet); - continue; - } - - const { sheetsMap, danglingDataMap } = processSheetData(sheetData, hierarchyLevelIndex); - - // Combine danglingDataMap with sheetsMap - for (const key of Object.keys(danglingDataMap)) { - if (sheetsMap[key]) { - sheetsMap[key].data = [sheetData[0], ...danglingDataMap[key], ...sheetsMap[key].data.slice(1)]; - } else { - sheetsMap[key] = { - sheetName: key, - data: [...danglingDataMap[key], sheetData[0]], - }; - } - } - - // Add sheetsMap values to result - result.push(...Object.values(sheetsMap)); - } - - return result.length > 0 ? result : xlsxData; // Return result or original data if result is empty -}; - -// Function to process sheet data and return sheetsMap and danglingDataMap -const processSheetData = (sheetData, hierarchyLevelIndex) => { - const sheetsMap = {}; - const danglingDataMap = {}; - let emptyHierarchyRow = []; - let lastWasEmpty = true; - - // Iterate through sheet data starting from the second row (skipping header) - for (let i = 1; i < sheetData.length; i++) { - const row = sheetData[i]; - const hierarchyValue = row[hierarchyLevelIndex]; - - if (emptyHierarchyRow.length && hierarchyValue !== "") { - danglingDataMap[hierarchyValue] = emptyHierarchyRow; - } - - if (hierarchyValue === "" && lastWasEmpty) { - emptyHierarchyRow.push(row); - } else { - emptyHierarchyRow = []; - } - - if (!sheetsMap[hierarchyValue] && hierarchyValue !== "") { - sheetsMap[hierarchyValue] = { - sheetName: hierarchyValue, - data: [sheetData[0]], - }; - } - - if (hierarchyValue === row[hierarchyLevelIndex] && hierarchyValue !== "") { - sheetsMap[hierarchyValue].data.push(row); - } - - lastWasEmpty = hierarchyValue === ""; - } - - return { sheetsMap, danglingDataMap }; -}; - -export const filterBoundaries = (boundaryData, boundaryFilters) => { - if (!boundaryFilters) return boundaryData; - // Define a helper function to recursively filter boundaries - function filterRecursive(boundary) { - // Find the filter that matches the current boundary - const filter = boundaryFilters?.find((f) => f.code === boundary.code && f.type === boundary.boundaryType); - - // If no filter is found, return the boundary with its children filtered recursively - if (!filter) { - return { - ...boundary, - children: boundary.children.map(filterRecursive), - }; - } - - // If the boundary has no children, handle the case where includeAllChildren is false - if (!boundary.children.length) { - // Return the boundary with an empty children array - return { - ...boundary, - children: [], - }; - } - - // If includeAllChildren is true, return the boundary with all children - if (filter.includeAllChildren) { - return { - ...boundary, - children: boundary.children.map(filterRecursive), - }; - } - - // Filter children based on the filters - const filteredChildren = boundary.children - .filter((child) => boundaryFilters.some((f) => f.code === child.code && f.type === child.boundaryType)) - .map(filterRecursive); - - // Return the boundary with filtered children - return { - ...boundary, - children: filteredChildren, - }; - } - - // Map through the boundary data and apply the recursive filter function to each boundary - const filteredData = boundaryData.map(filterRecursive); - return filteredData; -}; - -/** - * Retrieves all facilities for a given tenant ID. - * @param tenantId The ID of the tenant. - * @returns An array of facilities. - */ -async function getAllFacilities(tenantId) { - // Retrieve all facilities for the given tenant ID - const facilitySearchBody = { - Facility: { isPermanent: true }, - }; - - const facilitySearchParams = { - limit: 50, - offset: 0, - tenantId: tenantId, - }; - - const searchedFacilities = []; - let searchAgain = true; - - while (searchAgain) { - const response = await getFacilities(facilitySearchParams, facilitySearchBody); - if (response) { - searchAgain = response.length >= 50; - searchedFacilities.push(...response); - facilitySearchParams.offset += 50; - } else searchAgain = false; - } - - return searchedFacilities; -} - -const addFacilitySheet = (xlsxData, mapping, facilities, schema, t) => { - if (!mapping) return xlsxData; - // Create header row - const headers = Object.keys(mapping); - - // Create data rows - const dataRow = []; - for (const facility of facilities) { - facility.isPermanent = facility.isPermanent ? t("PERMAENENT") : t("TEMPORARY"); - dataRow.push(headers.map((header) => facility[mapping[header]])); - } - headers.push(commonColumn); - const additionalCols = []; - if (schema?.schema?.Properties) { - const properties = Object.keys(schema.schema.Properties); - for (const col of properties) { - if (!headers.includes(col)) { - additionalCols.push(col); - } - } - } - headers.push(...additionalCols); - // Combine headers and data rows - const arrayOfArrays = [headers.map((item) => generateLocalisationKeyForSchemaProperties(item)), ...dataRow]; - - const facilitySheet = { - sheetName: FACILITY_DATA_SHEET, - data: arrayOfArrays, - }; - const updatedXlsxData = [facilitySheet, ...xlsxData]; - return updatedXlsxData; -}; - -const addReadMeSheet = (xlsxData, readMeData, readMeSheetName) => { - if (!readMeSheetName) return xlsxData; - const data = readMeData.reduce((acc, item) => { - if (item?.header) { - acc.push([item.header], ...(item.points || []).map((item) => [item]), [], [], [], []); - } - return acc; - }, []); - - const readMeSheet = { - sheetName: readMeSheetName, - data: [["MICROPLAN_TEMPLATE_README_MAIN_HEADER"], [], [], [], ...data], - }; - xlsxData.unshift(readMeSheet); - return xlsxData; -}; - -/** - * @param {Object} options - * @param {boolean} options.hierarchyLevelWiseSheets - * @param {string} options.hierarchyLevelName - * @param {boolean} options.addFacilityData - * @param {Object} options.schema - * @param {Object[]} options.boundaries - * @param {string} options.tenantId - * @param {string} options.hierarchyType - * @param {Object} options.readMeData - * @param {string} options.readMeSheetName - * @param {string} options.t // Assuming t is some context or translation object - */ -export const createTemplate = async ({ - hierarchyLevelWiseSheets = true, - hierarchyLevelName, - addFacilityData = false, - schema, - boundaries, - tenantId, - hierarchyType, - readMeData, - readMeSheetName, - t, -}) => { - // Fetch or retrieve boundary data - const filteredBoundaries = await fetchFilteredBoundaries(boundaries, tenantId, hierarchyType); - - // Initialize xlsxData array - let xlsxData = []; - - // Add boundary data to xlsxData - xlsxData = addBoundaryData(xlsxData, filteredBoundaries, hierarchyType); - - // Handle hierarchy level sheets - if (hierarchyLevelWiseSheets) { - xlsxData = devideXlsxDataHierarchyLevelWise(xlsxData, hierarchyLevelName); - } - - // Handle facility data addition - if (addFacilityData) { - xlsxData = await addFacilityDataToSheets(xlsxData, schema, tenantId, t); - } else { - // If no facility data, add schema data directly - xlsxData = addSchemaData(xlsxData, schema); - } - - // Add readme sheet data if provided - xlsxData = addReadMeSheet(xlsxData, readMeData, readMeSheetName); - - return xlsxData; -}; - -// Function to fetch filtered boundaries -const fetchFilteredBoundaries = async (boundaries, tenantId, hierarchyType) => { - const rootBoundary = boundaries?.find((boundary) => boundary.isRoot); - const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; - let boundaryData = sessionData.filteredBoundaries; - - if (!boundaryData) { - boundaryData = await fetchBoundaryData(tenantId, hierarchyType, rootBoundary?.code); - const filteredBoundaries = await filterBoundaries(boundaryData, boundaries); - Digit.SessionStorage.set("microplanHelperData", { - ...sessionData, - filteredBoundaries: filteredBoundaries, - }); - return filteredBoundaries; - } - return boundaryData; -}; - -// Function to add facility data to sheets -const addFacilityDataToSheets = async (xlsxData, schema, tenantId, t) => { - const facilities = await getAllFacilities(tenantId); - if (schema?.template?.facilitySchemaApiMapping) { - return addFacilitySheet(xlsxData, schema.template.facilitySchemaApiMapping, facilities, schema, t); - } - // If no specific facility schema mapping, add default facility data - const facilitySheet = { - sheetName: FACILITY_DATA_SHEET, - data: [], - }; - return addSchemaData([facilitySheet], schema); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js deleted file mode 100644 index b50b2ad48a6..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js +++ /dev/null @@ -1,150 +0,0 @@ -import { SHEET_PASSWORD, UNPROTECT_TILL_ROW } from "../configs/constants"; - -export function updateFontNameToRoboto(worksheet) { - worksheet.eachRow({ includeEmpty: true }, (row) => { - row.eachCell({ includeEmpty: true }, (cell) => { - // Preserve existing font properties - const existingFont = cell.font || {}; - - // Update only the font name to Roboto - cell.font = { - ...existingFont, // Spread existing properties - name: "Roboto", // Update the font name - }; - }); - }); -} - -export const freezeWorkbookValues = async (workbook) => { - workbook.eachSheet((worksheet) => { - worksheet.eachRow((row) => { - row.eachCell((cell) => { - // Lock each cell - cell.protection = { - locked: true, - }; - }); - }); - // Protect the worksheet - worksheet.protect(SHEET_PASSWORD, { - selectLockedCells: true, - selectUnlockedCells: true, - }); - }); - - return workbook; -}; - -export const unfreezeColumnsByHeader = async (workbook, headers) => { - workbook.eachSheet((worksheet) => { - const headerRow = worksheet.getRow(1); // Assuming headers are in the first row - const columnsToUnfreeze = []; - - headerRow.eachCell((cell, colNumber) => { - if (headers.includes(cell.value)) { - columnsToUnfreeze.push(colNumber); - } - }); - - worksheet.eachRow((row, rowNumber) => { - if (rowNumber === 1) return; - columnsToUnfreeze.forEach((colNumber) => { - const cell = row.getCell(colNumber); - cell.protection = { - locked: false, - }; - }); - }); - - // Re-protect the worksheet after modifying cell protection - worksheet.protect(SHEET_PASSWORD, { - selectLockedCells: true, - selectUnlockedCells: true, - }); - }); - - return workbook; -}; - -export const freezeSheetValues = async (workbook, sheetName) => { - const worksheet = workbook.getWorksheet(sheetName); - if (worksheet) { - worksheet.eachRow((row) => { - row.eachCell((cell) => { - // Lock each cell - cell.protection = { - locked: true, - }; - }); - }); - // Protect the worksheet - worksheet.protect(SHEET_PASSWORD, { - selectLockedCells: true, - selectUnlockedCells: true, - }); - } - - return workbook; -}; - -export const freezeCellsWithData = async (workbook, sheetName) => { - const worksheet = workbook.getWorksheet(sheetName); - if (worksheet) { - worksheet.eachRow((row) => { - row.eachCell((cell) => { - if (cell.value) { - // Check if the cell has data - cell.protection = { - locked: true, - }; - } else { - cell.protection = { - locked: false, - }; - } - }); - }); - // Protect the worksheet - worksheet.protect(SHEET_PASSWORD, { - selectLockedCells: true, - selectUnlockedCells: true, - }); - } - - return workbook; -}; -export const performUnfreezeCells = async (workbook, sheetName) => { - const sheet = workbook.getWorksheet(sheetName); - - let lastFilledColumn = 1; - sheet.getRow(1).eachCell((cell, colNumber) => { - if (cell.value !== undefined && cell.value !== null && cell.value !== "") { - lastFilledColumn = colNumber; - } - }); - - for (let row = 1; row <= parseInt(UNPROTECT_TILL_ROW); row++) { - for (let col = 1; col <= lastFilledColumn; col++) { - const cell = sheet.getCell(row, col); - if (!cell.value && cell.value !== 0) { - cell.protection = { locked: false }; - } - } - } - sheet.protect(SHEET_PASSWORD, { selectLockedCells: true, selectUnlockedCells: true }); -}; - -export const hideUniqueIdentifierColumn = async (workbook, sheetName, column) => { - const sheet = workbook.getWorksheet(sheetName); - for (const item of column) { - let colIndex; - sheet.getRow(1).eachCell((cell, colNumber) => { - if (cell.value === item) { - colIndex = colNumber; - } - }); - if (column && sheet.getColumn(colIndex)) { - sheet.getColumn(colIndex).hidden = true; - } - } -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js deleted file mode 100644 index 0d2a344a8f1..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js +++ /dev/null @@ -1,199 +0,0 @@ -import Ajv from "ajv"; -const ajv = new Ajv({ allErrors: true }); -ajv.addKeyword("isRequired"); -ajv.addKeyword("isLocationDataColumns"); -ajv.addKeyword("isRuleConfigureInputs"); -ajv.addKeyword("isFilterPropertyOfMapSection"); -ajv.addKeyword("isVisualizationPropertyOfMapSection"); -ajv.addKeyword("toShowInMicroplanPreview"); - -// Function responsible for excel data validation with respect to the template/schema provided -const translateSchema = (schemaData) => { - const required = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRequired) { - acc.push(key); - } - return acc; - }, []); - - return { required, properties: schemaData.Properties }; -}; - -const createSchema = (properties, required) => { - return { - type: "object", - patternProperties: { - ".*": { - type: "array", - items: { - type: "object", - properties: properties, - required: required, - additionalProperties: true, - }, - }, - }, - minProperties: 1, - additionalProperties: false, - }; -}; - -const extractLocationDataColumns = (schemaData) => { - return Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isLocationDataColumns) { - acc.push(key); - } - return acc; - }, []); -}; - -const setNestedError = (errors, path, error) => { - if (!path.length) return; - - let current = errors; - for (let i = 0; i < path.length - 1; i++) { - if (!current[path[i]]) { - current[path[i]] = {}; - } - current = current[path[i]]; - } - - if (!current[path[path.length - 1]]) { - current[path[path.length - 1]] = []; - } - - current[path[path.length - 1]] = [...new Set([...current[path[path.length - 1]], error])]; -}; - -const formatErrors = (validateExcelErrors, locationDataColumns, t) => { - const errors = {}; - let hasDataErrors = "false"; // true, false, missing_properties, unknown - const missingColumnsList = new Set(); - let errorMessages = {}; - - validateExcelErrors.forEach((error) => { - let tempErrorStore = ""; - let instancePathTypeGlobal; - - switch (error.keyword) { - case "additionalProperties": - tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES"; - hasDataErrors = "true"; - break; - case "type": - { - const instancePathType = error.instancePath.split("/"); - const neededType = error.params?.type; - instancePathTypeGlobal = instancePathType; - tempErrorStore = locationDataColumns.includes(instancePathType[instancePathType.length - 1]) - ? "ERROR_INCORRECT_LOCATION_COORDINATES" - : neededType === "number" - ? "ERROR_MUST_BE_A_NUMBER" - : "ERROR_MUST_BE_A_STRING"; - hasDataErrors = "true"; - } - break; - case "required": - { - const missing = error.params.missingProperty; - const instancePathType = error.instancePath.split("/"); - instancePathTypeGlobal = [...instancePathType, missing]; - tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY"; - missingColumnsList.add(missing); - hasDataErrors = "true"; - } - break; - case "maximum": - case "minimum": - { - const instancePathMinMax = error.instancePath.split("/"); - instancePathTypeGlobal = instancePathMinMax; - tempErrorStore = locationDataColumns.includes(instancePathMinMax[instancePathTypeGlobal.length - 1]) - ? "ERROR_INCORRECT_LOCATION_COORDINATES" - : "ERROR_DATA_EXCEEDS_LIMIT_CONSTRAINTS"; - hasDataErrors = "true"; - } - break; - case "pattern": - tempErrorStore = "ERROR_VALUE_NOT_ALLOWED"; - hasDataErrors = "true"; - break; - case "minProperties": - hasDataErrors = "minProperties"; - break; - case "enum": - { - const instancePathType = error.instancePath.split("/"); - instancePathTypeGlobal = instancePathType; - tempErrorStore = { - error: "ERROR_UPLOAD_DATA_ENUM", - values: { allowedValues: error.params?.allowedValues?.map((item) => t(item)).join(", ") }, - }; - hasDataErrors = "true"; - } - break; - default: - hasDataErrors = "unknown"; - } - - if (tempErrorStore && instancePathTypeGlobal) { - setNestedError(errors, instancePathTypeGlobal.slice(1, 4), tempErrorStore); - } - - switch (hasDataErrors) { - case "true": - errorMessages = { dataError: "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS" }; - break; - case "minProperties": - errorMessages = { minProperties: "ERROR_UPLOADED_DATA_IS_EMPTY" }; - break; - case "unknown": - errorMessages = { unknown: "ERROR_UNKNOWN" }; - break; - case "false": - break; - } - }); - - return { - valid: !hasDataErrors, - message: errorMessages ? [...new Set(Object.values(errorMessages))] : [], - errors, - missingColumnsList, - }; -}; - -export const excelValidations = (data, schemaData, t) => { - const { required, properties } = translateSchema(schemaData); - const schema = createSchema(properties, required); - const validateExcel = ajv.compile(schema); - const valid = validateExcel(data); - const locationDataColumns = extractLocationDataColumns(schemaData); - - if (!valid) { - const validationResult = formatErrors(validateExcel.errors, locationDataColumns, t); - ajv.removeSchema(); - return validationResult; - } - - ajv.removeSchema(); - return { valid }; -}; - -export const checkForErrorInUploadedFileExcel = async (fileInJson, schemaData, t) => { - try { - const valid = excelValidations(fileInJson, schemaData, t); - if (valid.valid) { - return { valid: true }; - } - return { - valid: false, - message: valid.message, - errors: valid.errors, - missingProperties: valid.missingColumnsList, - }; - } catch (error) { - console.error("Error in excel validations: ", error?.message); - return { valid: false, message: ["ERROR_PARSING_FILE"] }; - } -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js deleted file mode 100644 index f2d4f277ba6..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js +++ /dev/null @@ -1,99 +0,0 @@ -import ExcelJS from "exceljs"; - -// input is a xlsx blob -// options {header} -// header: true -> have seperate header so data will be in key: value pair -export const parseXlsxToJsonMultipleSheets = async (file, options = {}) => { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.onload = async (event) => { - try { - const arrayBuffer = event.target.result; - const workbook = await loadWorkbook(arrayBuffer); - const jsonData = processWorkbook(workbook, options); - resolve(jsonData); - } catch (error) { - console.error(error); - resolve({ error: true }); - } - }; - - reader.onerror = (error) => { - console.error(error); - resolve({ error: true, details: error }); - }; - - reader.readAsArrayBuffer(file); - }); -}; - -const loadWorkbook = async (arrayBuffer) => { - const workbook = new ExcelJS.Workbook(); - await workbook.xlsx.load(arrayBuffer); - return workbook; -}; - -const processWorkbook = (workbook, options) => { - const jsonData = {}; - workbook.eachSheet((worksheet) => { - const jsonSheetData = processSheet(worksheet, options); - if (jsonSheetData.length !== 0 && jsonSheetData?.[0].length !== 0) { - jsonData[worksheet.name] = jsonSheetData; - } - }); - return jsonData; -}; - -const processSheet = (worksheet, options) => { - const jsonSheetData = []; - let headers = []; - - worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => { - const rowData = cleanRowData(row.values); - if (options.header && rowNumber === 1) { - headers = rowData; - } else if (options.header && headers.length > 0) { - jsonSheetData.push(mapRowToHeaders(rowData, headers)); - } else { - jsonSheetData.push(rowData); - } - }); - - removeTrailingEmptyRows(jsonSheetData); - return jsonSheetData; -}; - -const cleanRowData = (rowData) => { - return rowData.slice(1).map((cell) => (typeof cell === "string" ? cell.trim() : cell)); -}; - -const mapRowToHeaders = (rowData, headers) => { - const rowObject = {}; - headers.forEach((header, index) => { - rowObject[header] = rowData[index]; - }); - return rowObject; -}; - -const removeTrailingEmptyRows = (data) => { - while (data.length > 0) { - const lastRow = data[data.length - 1]; - const isEmptyRow = checkIfRowIsEmpty(lastRow); - if (isEmptyRow) { - data.pop(); - } else { - break; - } - } -}; - -const checkIfRowIsEmpty = (row) => { - if (Array.isArray(row)) { - return row.filter((item) => item !== "").length === 0; - } - if (typeof row === "object" && row !== null) { - return Object.values(row).filter((item) => item !== "").length === 0; - } - return false; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js deleted file mode 100644 index 42a465740b5..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js +++ /dev/null @@ -1,234 +0,0 @@ -import gjv from "geojson-validation"; -import Ajv from "ajv"; -const ajv = new Ajv({ allErrors: true }); -ajv.addKeyword("isRequired"); -ajv.addKeyword("isLocationDataColumns"); -ajv.addKeyword("isRuleConfigureInputs"); -ajv.addKeyword("isFilterPropertyOfMapSection"); -ajv.addKeyword("isVisualizationPropertyOfMapSection"); -ajv.addKeyword("toShowInMicroplanPreview"); - -//the postion must be valid point on the earth, x between -180 and 180 -gjv.define("Position", (position) => { - let errors = []; - if (position[0] < -180 || position[0] > 180) { - errors.push("Location Coordinates Error: the x must be between -180 and 180"); - } - if (position[1] < -90 || position[1] > 90) { - errors.push("Location Coordinates Error: the y must be between -90 and 90"); - } - return errors; -}); - -// Main functino for geojson validation that includes structural and property validations -export const geojsonValidations = (data, schemaData, t) => { - const valid = geojsonStructureValidation(data); - return valid.valid ? { valid: true } : { valid: false, message: valid.message || ["ERROR_INVALID_GEOJSON"] }; -}; - -// Funciton responsible for structural verification of geojson data -export const geojsonStructureValidation = (data) => { - let valid = true; - const trace = {}; - for (let i = 0; i < data["features"].length; i++) { - const check = gjv.valid(data["features"][i]); - valid = valid && check; - const errors = gjv.isFeature(data["features"][i], true); - // check if the location coordinates are according to the provided guidlines - if (errors.some((str) => str.includes("Location Coordinates Error:"))) return { valid: false, message: ["ERROR_INCORRECT_LOCATION_COORDINATES"] }; - if (!check) trace[i] = [errors]; - // let error; - // Object.keys(data["features"][i]["properties"]).forEach((j) => { - // if (j.length > 10) error = { valid: false, trace, message: ["ERROR_FIELD_NAME"] }; - // return j; - // }); - // if (error) return error; - } - return { valid, trace }; -}; - -const geometryValidation = (data) => { - let firstType; - for (const feature of data.features) { - if (!feature.geometry || !feature.geometry.type) { - return false; // Missing geometry or geometry type - } - if (!firstType) { - firstType = feature.geometry.type; - } else { - // Check if the current geometry type matches the first one - if (feature.geometry.type !== firstType) { - return false; // Different geometry types found - } - } - } - return true; -}; - -// Function responsible for property verification of geojson data -export const geojsonPropertiesValidation = (data, schemaData, name, t) => { - const translate = () => { - const required = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRequired) { - acc.push(key); - } - return acc; - }, []); - - // const properties = prepareProperties(schemaData.Properties, t); - return { required, properties: schemaData.Properties }; - }; - const { required, properties } = translate(); - const schema = { - type: "object", - properties: { - type: { const: "FeatureCollection" }, - }, - patternProperties: { - "^features$": { - type: "array", - items: { - type: "object", - patternProperties: { - "^properties$": { - type: "object", - patternProperties: properties, - required: required, - additionalProperties: true, - }, - }, - }, - }, - }, - additionalProperties: true, - }; - const validateGeojson = ajv.compile(schema); - const valid = validateGeojson(data); - const errors = {}; - let hasDataErrors = "false"; // true, false, missing_properties, unknown - const missingColumnsList = new Set(); - let errorMessages = []; - if (!valid) { - for (let i = 0; i < validateGeojson.errors.length; i++) { - let tempErrorStore = ""; - let instancePathTypeGlobal = validateGeojson.errors[i].instancePath.split("/"); - switch (validateGeojson.errors[i].keyword) { - case "additionalProperties": { - tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES"; - hasDataErrors = "true"; - break; - } - case "type": - { - const instancePathType = validateGeojson.errors[i].instancePath.split("/"); - const neededType = validateGeojson.errors[i].params?.type; - instancePathTypeGlobal = instancePathType; - tempErrorStore = neededType === "number" ? "ERROR_MUST_BE_A_NUMBER" : "ERROR_MUST_BE_A_STRING"; - hasDataErrors = "true"; - } - break; - case "const": { - if (validateGeojson.errors[i].params.allowedValue === "FeatureCollection") tempErrorStore = "ERROR_FEATURECOLLECTION"; - hasDataErrors = "true"; - break; - } - case "required": { - const missing = validateGeojson.errors[i].params.missingProperty; - const instancePathType = validateGeojson.errors[i].instancePath.split("/"); - instancePathTypeGlobal = [...instancePathType, missing]; - tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY"; - missingColumnsList.add(missing); - // hasDataErrors = "missing_properties"; - hasDataErrors = "true"; - break; - } - case "pattern": - tempErrorStore = "ERROR_VALUE_NOT_ALLOWED"; - hasDataErrors = "true"; - break; - case "minProperties": { - hasDataErrors = "minProperties"; - break; - } - case "enum": { - const instancePathType = validateGeojson.errors[i].instancePath.split("/"); - instancePathTypeGlobal = instancePathType; - tempErrorStore = { - error: "ERROR_UPLOAD_DATA_ENUM", - values: { allowedValues: validateGeojson.errors[i]?.params?.allowedValues?.map((item) => t(item)).join(", ") }, - }; - hasDataErrors = "true"; - break; - } - default: - hasDataErrors = "unknown"; - break; - } - if (tempErrorStore) - errors[name] = { - ...(errors[name] ? errors[name] : {}), - [instancePathTypeGlobal[2]]: { - ...(errors?.[name]?.[instancePathTypeGlobal[2]] ? errors?.[name]?.[instancePathTypeGlobal[2]] : {}), - [instancePathTypeGlobal[4]]: [ - ...new Set( - ...(errors?.[name]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[4]] - ? errors?.[name]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[4]] - : []) - ), - tempErrorStore, - ], - }, - }; - - switch (hasDataErrors) { - case "true": - errorMessages = { ...errorMessages, dataError: t("ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") }; - break; - case "unknown": - errorMessages = { ...errorMessages, unkown: t("ERROR_UNKNOWN") }; - break; - case "missing_properties": - errorMessages = { - ...errorMessages, - missingProperty: t("ERROR_MISSING_PROPERTY", { properties: [...missingColumnsList].map((item) => t(item)).join(", ") }), - }; - break; - case "false": - break; - } - } - - ajv.removeSchema(); - return { - valid: !hasDataErrors, - message: errorMessages ? [...new Set(Object.values(errorMessages))] : [], - errors, - validationError: validateGeojson.errors, - }; - } - ajv.removeSchema(); - if (!geometryValidation(data)) return { valid: false, message: t("ERROR_MULTIPLE_GEOMETRY_TYPES") }; - return { valid: true }; -}; - -//////////////////////////// -// // Might be needed -// function filterOutWordAndLocalise(inputString, operation) { -// // Define a regular expression to match the string parts -// var regex = /(\w+)/g; // Matches one or more word characters - -// // Replace each match using the provided function -// var replacedString = inputString.replace(regex, function (match) { -// // Apply the function to each matched string part -// return operation(match); -// }); - -// return replacedString; -// } -// const prepareProperties = (properties, t) => { -// let newProperties = {}; -// Object.keys(properties).forEach((item) => (newProperties[filterOutWordAndLocalise(item, t)] = properties[item])); -// return newProperties; -// }; - -//////////////////////////// diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js deleted file mode 100644 index 0d21a93ca46..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js +++ /dev/null @@ -1,478 +0,0 @@ -import _ from "lodash"; -import { findChildren, findParent } from "../utils/processHierarchyAndData"; -import { EXCEL, LOCALITY, commonColumn } from "../configs/constants"; - -const formatDates = (value, type) => { - let newValue = value; - if (type !== "EPOC" && (!newValue || Number.isNaN(Number(newValue)))) { - newValue = new Date(); - } - switch (type) { - case "date": - return new Date(newValue)?.toISOString?.()?.split?.("T")?.[0]; - case "datetime": - return new Date(newValue).toISOString(); - case "EPOC": - return String(new Date(newValue)?.getTime()); - } -}; - -// get schema for validation -const getSchema = (campaignType, type, section, schemas) => { - if (!campaignType || !type || !section || !schemas) return {}; - return schemas.find((schema) => { - if (!schema.campaignType) { - return schema.type === type && schema.section === section; - } - return schema.campaignType === campaignType && schema.type === type && schema.section === section; - }); -}; - -// Sorting 2 lists, The first list is a list of string and second one is list of Objects -const sortSecondListBasedOnFirstListOrder = (firstList, secondList) => { - if (!firstList) return []; - // Create a map to store the indices of elements in the first list - const indexMap = {}; - firstList.forEach((value, index) => { - indexMap[value] = index; - }); - - // Sort the second list based on the order of elements in the first list - secondList.sort((objecta, objectb) => { - // Get the mappedTo values of each object - const mappedToA = objecta.mappedTo; - const mappedToB = objectb.mappedTo; - - // Get the indices of mappedTo values in the first list - const indexA = indexMap[mappedToA]; - const indexB = indexMap[mappedToB]; - - // Compare the indices - return indexA - indexB; - }); - - return secondList; -}; - -const computeGeojsonWithMappedProperties = ({ campaignType, fileType, templateIdentifier, validationSchemas }) => { - const schemaData = getSchema(campaignType, fileType, templateIdentifier, validationSchemas); - let schemaKeys; - if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"])); - // Sorting the resourceMapping list inorder to maintain the column sequence - const sortedSecondList = sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); - // Creating a object with input data with MDMS keys - const newFeatures = fileData.data["features"].map((item) => { - const newProperties = sortedSecondList.reduce( - (acc, e) => ({ - ...acc, - [e["mappedTo"]]: item["properties"][e["mappedFrom"]], - }), - {} - ); - item["properties"] = newProperties; - return item; - }); - const data = fileData.data; - data["features"] = newFeatures; - return data; -}; - -const destroySessionHelper = (currentPath, pathList, sessionName) => { - if (!pathList.includes(currentPath)) { - sessionStorage.removeItem(`Digit.${sessionName}`); - } -}; - -const convertGeojsonToExcelSingleSheet = (InputData, fileName) => { - if (!InputData || !Array.isArray(InputData) || InputData.length === 0) { - return null; - } - - // Extract keys from the first feature's properties - const keys = Object.keys(InputData?.[0]?.properties); - - if (!keys || keys.length === 0) { - return null; - } - - // Extract corresponding values for each feature - const values = InputData?.map((feature) => { - return keys.map((key) => feature.properties[key]); - }); - - // Group keys and values into the desired format - return { [fileName]: [keys, ...values] }; -}; - -const areObjectsEqual = (obj1, obj2) => { - return obj1.name === obj2.name && obj1.code === obj2.code; -}; - -const computeDifferences = (data1, data2) => { - const removed = {}; - const added = {}; - - for (const key in data1) { - if (Object.hasOwn(data2, key)) { - removed[key] = data1[key].filter((item1) => !data2[key].some((item2) => areObjectsEqual(item1, item2))); - added[key] = data2[key].filter((item2) => !data1[key].some((item1) => areObjectsEqual(item1, item2))); - } else { - removed[key] = data1[key]; - added[key] = []; - } - } - - for (const key in data2) { - if (!data1.hasOwnProperty(key)) { - added[key] = data2[key]; - removed[key] = []; - } - } - - return { removed, added }; -}; - -const extractNames = (data) => { - return Object.values(data) - .flatMap((items) => items) - .filter((item) => item.name) - .map((item) => item.name); -}; -// function that handles dropdown selection. used in: mapping and microplan preview -const handleSelection = (e, boundaryType, boundarySelections, hierarchy, setBoundarySelections, boundaryData, setIsLoading) => { - setIsLoading(true); - if (!e || !boundaryType) return; - const selections = e.map((item) => item?.[1]); - const newComputedSelection = { ...boundarySelections, [boundaryType]: selections }; - const { removed, added } = computeDifferences(boundarySelections, newComputedSelection); - // for(const item in removed){ - if (removed && Object.keys(removed).length !== 0 && Object.values(removed)?.flatMap((item) => item).length !== 0) { - const filteredRemoved = extractNames(removed); - const children = Object.values(findChildren(filteredRemoved, Object.values(boundaryData)?.[0]?.hierarchicalData))?.map((item) => item?.name); - for (const key in newComputedSelection) { - newComputedSelection[key] = newComputedSelection[key].filter((item) => !children.includes(item?.name)); - } - } - setBoundarySelections(newComputedSelection); -}; - -// Preventing default action when we scroll on input[number] is that it increments or decrements the number -const inputScrollPrevention = (e) => { - e.target.addEventListener("wheel", (e) => e.preventDefault(), { passive: false }); -}; - -const mapDataForApi = (data, Operators, microplanName, campaignId, status, reqType = "update") => { - const files = extractFiles(data, reqType); - const resourceMapping = extractResourceMapping(data, reqType); - const assumptions = extractAssumptions(data, reqType); - const operations = extractOperations(data, Operators, reqType); - - return createApiRequestBody(status, microplanName, campaignId, files, assumptions, operations, resourceMapping); -}; - -const extractFiles = (data, reqType) => { - const files = []; - if (data && data.upload) { - Object.values(data.upload).forEach((item) => { - if (isValidFile(item, reqType)) { - files.push(mapFile(item)); - } - }); - } - return files; -}; - -const isValidFile = (item, reqType) => { - if (!item || item.error || !item.filestoreId) return false; - if (reqType === "create" && !item.active) return false; - return true; -}; - -const mapFile = (item) => ({ - active: item.active, - filestoreId: item.filestoreId, - inputFileType: item.fileType, - templateIdentifier: item.section, - id: item.fileId, -}); - -const extractResourceMapping = (data, reqType) => { - let resourceMapping = []; - if (data && data.upload) { - Object.values(data.upload).forEach((item) => { - if (isValidResourceMapping(item, reqType)) { - resourceMapping.push(item.resourceMapping); - } - }); - resourceMapping = resourceMapping.flat(); - } - return resourceMapping; -}; - -const isValidResourceMapping = (item, reqType) => { - if (reqType === "create" && item.resourceMapping && item.resourceMapping.every((i) => i.active === false)) return false; - if (!item || !item.resourceMapping || item.error || !Array.isArray(item.resourceMapping)) return false; - if (!item.resourceMapping.every((i) => i.mappedFrom && i.mappedTo)) return false; - return true; -}; - -const extractAssumptions = (data, reqType) => { - if (!data || !data.hypothesis) return []; - return data.hypothesis.reduce((acc, item) => { - if (isValidAssumption(item, reqType)) { - acc.push({ ...item }); - } - return acc; - }, []); -}; - -const isValidAssumption = (item, reqType) => { - if (reqType === "create" && !item.active) return false; - if (!item.key || !item.value) return false; - return true; -}; - -const extractOperations = (data, Operators, reqType) => { - if (!data || !data.ruleEngine) return []; - return data.ruleEngine.reduce((acc, item) => { - if (isValidOperation(item, reqType)) { - acc.push(mapOperation(item, Operators)); - } - return acc; - }, []); -}; - -const isValidOperation = (item, reqType) => { - if (reqType === "create" && !item.active) return false; - if (!item.active && !item.input) return true; - if (!item.active && !item.operator && !item.output && !item.input && !item.assumptionValue) return false; - return true; -}; - -const mapOperation = (item, Operators) => { - const data = { ...item }; - const operator = Operators.find((e) => e.name === data.operator); - if (operator && operator.code) data.operator = operator.code; - if (data.oldInput) data.input = data.oldInput; - return data; -}; - -const createApiRequestBody = (status, microplanName, campaignId, files, assumptions, operations, resourceMapping) => ({ - PlanConfiguration: { - status, - tenantId: Digit.ULBService.getStateId(), - name: microplanName, - executionPlanId: campaignId, - files, - assumptions, - operations, - resourceMapping, - }, -}); - -const addResourcesToFilteredDataToShow = (previewData, resources, hypothesisAssumptionsList, formulaConfiguration, userEditedResources, t) => { - // Clone the preview data to avoid mutating the original data - const data = _.cloneDeep(previewData); - - // Helper function to check for user-edited data - const checkUserEditedData = (commonColumnData, resourceName) => { - if (userEditedResources && userEditedResources[commonColumnData]) { - return userEditedResources[commonColumnData][resourceName]; - } - }; - - // Ensure the previewData has at least one row and the first row is an array - if (!Array.isArray(data) || !Array.isArray(data[0])) { - return []; - } - - // Identify the index of the common column - const conmmonColumnIndex = data[0].indexOf(commonColumn); - if (conmmonColumnIndex === -1) { - return []; - } - - // Ensure resources is a valid array - if (!Array.isArray(resources)) { - return data; - } - - // Process each row of the data - const combinedData = data.map((item, index) => { - if (!Array.isArray(item)) { - return item; - } - - if (index === 0) { - // Add resource names to the header row - resources.forEach((e) => item.push(e)); - return item; - } - - // Process each resource for the current row - resources.forEach((resourceName, resourceIndex) => { - let savedData = checkUserEditedData(item[conmmonColumnIndex], resourceName); - if (savedData !== undefined) { - item.push(savedData); - } else { - let calculations = calculateResource(resourceName, item, formulaConfiguration, previewData[0], hypothesisAssumptionsList, t); - if (calculations !== null) calculations = Math.round(calculations); - item.push(calculations !== null && calculations !== undefined ? calculations : undefined); - } - }); - - return item; - }); - - return combinedData; -}; - -const calculateResource = (resourceName, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t) => { - let formula = formulaConfiguration?.find((item) => item?.active && item?.output === resourceName); - if (!formula) return null; - - // Finding Input - // check for Uploaded Data - const inputValue = findInputValue(formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t); - if (inputValue === undefined || inputValue === null) return null; - const assumptionValue = hypothesisAssumptionsList?.find((item) => item?.active && item?.key === formula?.assumptionValue)?.value; - if (assumptionValue === undefined) return null; - - return findResult(inputValue, assumptionValue, formula?.operator); -}; - -// function to find input value, it calls calculateResource fucntion recurcively until it get a proper value -const findInputValue = (formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t) => { - const inputIndex = headers?.indexOf(formula?.input); - if (inputIndex === -1 || !rowData[inputIndex]) { - // let tempFormula = formulaConfiguration.find((item) => item?.output === formula?.input); - return calculateResource(formula?.input, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t); - } else return rowData[inputIndex]; -}; - -const findResult = (inputValue, assumptionValue, operator) => { - switch (operator) { - case "DEVIDED_BY": - if (assumptionValue === 0) return; - return inputValue / assumptionValue; - case "MULTIPLIED_BY": - return inputValue * assumptionValue; - case "ADDITION": - return inputValue + assumptionValue; - case "SUBSTRACTION": - return inputValue - assumptionValue; - case "RAISE_TO": - return inputValue ** assumptionValue; - default: - return; - } -}; - -const fetchData = (state, campaignType) => { - let hypothesis = []; - let rulesOutputs = []; - let uploadList = []; - - hypothesis = state?.HypothesisAssumptions?.find((item) => item.campaignType === campaignType)?.assumptions; - rulesOutputs = state?.RuleConfigureOutput?.find((item) => item.campaignType === campaignType)?.data; - uploadList = state?.UploadConfiguration?.reduce((acc, item) => { - if (item.required) acc.push(item.id); - return acc; - }, []); - return { hypothesisList: hypothesis, rulesOutputs, uploadList }; -}; -const hypothesisCheck = (hypothesis, validList) => { - if (hypothesis && Array.isArray(hypothesis) && hypothesis.length !== 0 && validList && Array.isArray(validList) && validList.length !== 0) { - return hypothesis.filter((item) => item.active).every((item) => validList.includes(item.key)); - } - return false; -}; -const ruleOutputCheck = (rules, ruleOuputList) => { - if ( - rules && - Array.isArray(rules) && - rules.filter((item) => item.active).length !== 0 && - ruleOuputList && - Array.isArray(ruleOuputList) && - ruleOuputList.length !== 0 - ) { - return rules.filter((item) => item.active).every((item) => ruleOuputList.includes(item.output)); - } - return false; -}; -const emptyRuleCheck = (rules) => { - return !rules || rules.filter((item) => item.active && Object.values(item)?.filter((e) => e === "").length !== 0).length === 0; -}; -const ruleHypothesisCheck = (rules, ruleHypothesis) => { - if (rules && Array.isArray(rules) && rules.length !== 0 && ruleHypothesis && Array.isArray(ruleHypothesis) && ruleHypothesis.length !== 0) { - return rules.filter((item) => item.active).every((item) => ruleHypothesis.includes(item.assumptionValue)); - } - return false; -}; -const uploadCheck = (uploads, uploadList) => { - if (uploads && Array.isArray(uploads) && uploads.length !== 0 && uploadList && Array.isArray(uploadList) && uploadList.length !== 0) { - return uploads.some((item) => uploadList.includes(item.templateIdentifier) && item.active); - } - return false; -}; -const planConfigRequestBodyValidator = (data, state, campaignType) => { - if (!data || !campaignType || !state) return false; - - const { hypothesisList, rulesOutputs, uploadList } = fetchData(state, campaignType); - let checks = - // microplan name check - (!data || !data.name) && - hypothesisCheck(data?.PlanConfiguration?.assumptions, hypothesisList) && - emptyRuleCheck(data?.PlanConfiguration?.operations) && - ruleOutputCheck(data?.PlanConfiguration?.operations, rulesOutputs) && - ruleHypothesisCheck( - data?.PlanConfiguration?.operations, - data?.PlanConfiguration?.assumptions?.filter((item) => item.active)?.map((item) => item.key) - ) && - uploadCheck(data?.PlanConfiguration?.files, uploadList); - return checks; - // if() -}; - -const processDropdownForNestedMultiSelect = (dropDownOptions) => { - if (!dropDownOptions) return dropDownOptions; - const result = dropDownOptions.reduce((acc, item) => { - const { parent, ...rest } = item; - - // Find the group by parentBoundaryType - let group = acc.find((g) => g.name === parent?.name); - - // If not found, create a new group - if (!group) { - group = { name: parent?.name, options: [] }; - acc.push(group); - } - - // Add the item to the options of the found/created group - group.options.push(rest); - - return acc; - }, []); - return result; -}; - -const transformIntoLocalisationCode = (code) => { - return code?.toUpperCase(); -}; - -export default { - formatDates, - computeGeojsonWithMappedProperties, - destroySessionHelper, - mapDataForApi, - inputScrollPrevention, - handleSelection, - convertGeojsonToExcelSingleSheet, - sortSecondListBasedOnFirstListOrder, - addResourcesToFilteredDataToShow, - calculateResource, - planConfigRequestBodyValidator, - getSchema, - processDropdownForNestedMultiSelect, - transformIntoLocalisationCode, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js deleted file mode 100644 index ae470038a91..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js +++ /dev/null @@ -1,72 +0,0 @@ -import ExcelJS from "exceljs"; -import { SHEET_COLUMN_WIDTH } from "../configs/constants"; - -export const convertJsonToXlsx = async (jsonData, columnWithStyle, returnWorkbook = false) => { - const workbook = new ExcelJS.Workbook(); - - for (const [sheetName, data] of Object.entries(jsonData)) { - const worksheet = workbook.addWorksheet(sheetName); - populateWorksheet(worksheet, data, columnWithStyle); - } - - if (returnWorkbook) return workbook; - return await writeWorkbookToBuffer(workbook); -}; - -const populateWorksheet = (worksheet, data, columnWithStyle) => { - data.forEach((row, rowIndex) => { - const newRow = worksheet.addRow(row); - if (columnWithStyle?.errorColumn && rowIndex > 0) { - applyStyleToColumn(newRow, data[0], columnWithStyle); - } - }); - - styleHeaderRow(worksheet); - setColumnWidths(worksheet); -}; - -/** - * Applies a specified style to a column in a given row of a spreadsheet. - * - * @param {Object} newRow - The row object where the style will be applied. - * @param {Array} headerRow - The header row array containing column names. - * @param {Object} columnWithStyle - An object containing the column name and the style to be applied. - * @param {string} columnWithStyle.errorColumn - The name of the column where the style should be applied. - * @param {Object} columnWithStyle.style - The style properties to be applied to the cell. - */ -const applyStyleToColumn = (newRow, headerRow, columnWithStyle) => { - const errorColumnIndex = headerRow.indexOf(columnWithStyle.errorColumn); - if (errorColumnIndex !== -1) { - const columnIndex = errorColumnIndex + 1; - const newCell = newRow.getCell(columnIndex); - if (columnWithStyle.style && newCell) { - for (const key in columnWithStyle.style) { - newCell[key] = columnWithStyle.style[key]; - } - } - } -}; - -const styleHeaderRow = (worksheet) => { - const headerRow = worksheet.getRow(1); - if (headerRow) { - headerRow.font = { bold: true }; - } -}; - -const setColumnWidths = (worksheet) => { - // Iterate over all rows in the worksheet - worksheet.eachRow((worksheetRow, rowNumber) => { - worksheetRow.eachCell((cell, colNumber) => { - // Update column width based on the length of the cell's text - const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width - const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding - worksheet.getColumn(colNumber).width = newWidth; - }); - }); -}; - -export const writeWorkbookToBuffer = async (workbook) => { - const buffer = await workbook.xlsx.writeBuffer({ compression: true }); - return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js deleted file mode 100644 index f742ffd5e47..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js +++ /dev/null @@ -1,760 +0,0 @@ -import L from "leaflet"; -import "leaflet/dist/leaflet.css"; -import { processHierarchyAndData, findChildren, calculateAggregateForTree } from "../utils/processHierarchyAndData"; -import { EXCEL, GEOJSON, SHAPEFILE, MapChoroplethGradientColors } from "../configs/constants"; -import { PopulationSvg } from "../icons/Svg"; -import chroma from "chroma-js"; -import * as MicroplanIconCollection from "../icons/Svg"; -import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; - -const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs }; - -export const generatePreviewUrl = (baseMapUrl, center = [0, 0], zoom = 5) => { - const lon = Math.floor(((center[1] + 180) / 360) * Math.pow(0, zoom)); - const lat = Math.floor( - ((1 - Math.log(Math.tan((center[0] * Math.PI) / 180) + 1 / Math.cos((center[0] * Math.PI) / 180)) / Math.PI) / 2) * Math.pow(2, zoom) - ); - if (baseMapUrl) { - return baseMapUrl.replace("{z}", zoom).replace("{x}", lat).replace("{y}", lon); - } - // Return a default preview URL or handle this case as needed - return "default-preview-url.jpg"; // todo -}; - -// get schema for validation -export const getSchema = (campaignType, type, section, schemas) => { - return schemas.find((schema) => { - if (!schema.campaignType) { - return schema.type === type && schema.section === section; - } - return schema.campaignType === campaignType && schema.type === type && schema.section === section; - }); -}; - -export const calculateAggregateForTreeMicroplanWrapper = (entity) => { - if (!entity || typeof entity !== "object") return {}; - let newObject = {}; - for (let [key, value] of Object.entries(entity)) { - if (!value?.["hierarchicalData"]) continue; - let aggregatedTree = calculateAggregateForTree(value?.["hierarchicalData"]); - newObject[key] = { ...value, hierarchicalData: aggregatedTree }; - } - return newObject; -}; - -export const extractGeoData = ( - campaignType, - microplanData, - filterDataOrigin, - validationSchemas, - setToast, - setDataAvailability, - hierarchy, - setBoundaryData, - setFilterData, - setFilterProperties, - setFilterSelections, - setFilterPropertyNames, - state, - setChoroplethProperties, - setDataCompleteness, - t -) => { - if (!hierarchy) return; - - const initializeDataAvailability = (microplanData) => (microplanData?.upload ? "initialStage" : undefined); - - const checkFileActivity = (fileData) => fileData.active; - - const checkFileSection = (fileData, filterDataOrigin) => - filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section) || filterDataOrigin?.layerDataOrigin?.includes(fileData?.section); - - const getFileValidationSchema = (campaignType, fileData, validationSchemas) => - getSchema(campaignType, fileData?.fileType, fileData?.section, validationSchemas); - - const updateDataAvailabilityCheck = (dataAvailabilityCheck, condition, partialState) => - condition ? partialState : dataAvailabilityCheck === "initialStage" ? "false" : partialState; - - const handleFileDataError = (dataAvailabilityCheck, fileData) => - fileData?.error ? updateDataAvailabilityCheck(dataAvailabilityCheck, true, "partial") : dataAvailabilityCheck; - - const addResourcesToFilteredData = (data, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t) => - Digit.Utils.microplan.addResourcesToFilteredDataToShow( - data, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - microplanData?.microplanPreview?.userEditedResources || [], - t - ); - - const processFileData = ( - fileData, - schema, - filterDataOrigin, - virtualizationPropertiesCollector, - filterPropertiesCollector, - filterPropertieNameCollector, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - t - ) => { - const properties = Object.entries(schema?.schema?.Properties || {}); - const latLngColumns = []; - const filterProperty = []; - - for (const [key, value] of properties) { - if (value?.isLocationDataColumns) latLngColumns.push(t(key)); - if (filterDataOrigin?.layerDataOrigin?.includes(fileData?.section) && value?.isFilterPropertyOfMapSection) filterProperty.push(key); - if (value?.isVisualizationPropertyOfMapSection && filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section)) - virtualizationPropertiesCollector.add(key); - } - - filterProperty.forEach((property) => filterPropertieNameCollector.add(property)); - - return { latLngColumns, filterProperty }; - }; - - const processExcelFile = (fileData, latLngColumns, resources, formulaConfiguration, hypothesisAssumptionsList, schema, t) => { - let dataAvailabilityCheck = "true"; - const columnList = Object.values(fileData?.data)?.[0]?.[0]; - const check = latLngColumns.every((colName) => columnList.includes(t(colName))); - - if (!check) dataAvailabilityCheck = "partial"; - - let dataWithResources = Object.values(fileData?.data); - if (resources && formulaConfiguration && hypothesisAssumptionsList && schema?.showResourcesInMappingSection) { - dataWithResources = dataWithResources.map((item) => - addResourcesToFilteredData(item, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t) - ); - } - - const hasLocationData = dataWithResources.some((item) => item.some((row) => row.includes("lat") && row.includes("long"))); - - const convertedData = dataWithResources.map((item) => - item.map((row, rowIndex) => { - if (rowIndex === 0) { - if (row.indexOf("features") === -1) row.push("feature"); - return row; - } - const latIndex = item[0].findIndex((cell) => cell === "lat"); - const lonIndex = item[0].findIndex((cell) => cell === "long"); - const properties = item[0].reduce((acc, cell, index) => ({ ...acc, [cell]: row[index] }), {}); - const feature = - latIndex !== -1 && lonIndex !== -1 - ? { - type: "Feature", - properties, - geometry: { - type: "Point", - coordinates: [row[lonIndex], row[latIndex]], - }, - } - : null; - row.push(feature); - return row; - }) - ); - - return { dataAvailabilityCheck, hasLocationData, convertedData }; - }; - - const processGeoJsonFile = (fileData, filterProperty, resources, formulaConfiguration, hypothesisAssumptionsList, t) => { - const dataAvailabilityCheck = "true"; - const keys = [...Object.keys(fileData?.data.features[0].properties), "feature"]; - const values = fileData?.data.features.map((feature) => keys.map((key) => (key === "feature" ? feature : feature.properties[key] || null))); - - const dataWithResources = [[...keys, ...resources], ...values]; - const processedDataWithResources = dataWithResources.map((item, index) => { - if (index === 0) return item; - const newProperties = keys.reduce((acc, key, i) => (key !== "feature" ? { ...acc, [key]: item[i] } : acc), {}); - item[item.length - 1] = { ...item[item.length - 1], properties: newProperties }; - return item; - }); - - return { dataAvailabilityCheck, dataWithResources: processedDataWithResources }; - }; - - const updateFilterPropertiesCollector = (fileData, filterProperty, filterPropertiesCollector) => { - filterProperty.forEach((item) => { - Object.values(fileData?.data).forEach((data) => { - const filterPropertyIndex = data[0].indexOf(item); - if (filterPropertyIndex !== -1) data.slice(1).forEach((e) => filterPropertiesCollector.add(e[filterPropertyIndex])); - }); - }); - }; - - const setAvailabilityAndToastMessages = (dataAvailabilityCheck, combineList, files, setToast, t) => { - if (dataAvailabilityCheck === "true") { - const sectionWiseCheck = combineList.every((item) => Object.keys(files).includes(item)); - if (!sectionWiseCheck) dataAvailabilityCheck = "partial"; - } - - if (dataAvailabilityCheck === "initialStage" && (combineList.length === 0 || Object.keys(files).length === 0)) dataAvailabilityCheck = "false"; - - const toastMessages = { - false: { state: "warning", message: t("MAPPING_NO_DATA_TO_SHOW") }, - partial: { state: "warning", message: t("MAPPING_PARTIAL_DATA_TO_SHOW") }, - undefined: { state: "error", message: t("MAPPING_NO_DATA_TO_SHOW") }, - }; - - setToast(toastMessages[dataAvailabilityCheck]); - return dataAvailabilityCheck; - }; - - const setFinalDataAndProperties = ( - dataAvailabilityCheck, - setBoundary, - setFilter, - setBoundaryData, - setFilterData, - setFilterProperties, - setFilterSelections, - setFilterPropertyNames, - filterPropertiesCollector, - filterPropertieNameCollector, - virtualizationPropertiesCollector, - setChoroplethProperties, - resources - ) => { - setDataCompleteness(dataAvailabilityCheck); - setBoundary = calculateAggregateForTreeMicroplanWrapper(setBoundary); - setFilter = calculateAggregateForTreeMicroplanWrapper(setFilter); - setBoundaryData((previous) => ({ ...previous, ...setBoundary })); - setFilterData((previous) => ({ ...previous, ...setFilter })); - setFilterProperties([...filterPropertiesCollector]); - setFilterSelections([...filterPropertiesCollector]); - setFilterPropertyNames([...filterPropertieNameCollector]); - const tempVirtualizationPropertiesCollectorArray = [...virtualizationPropertiesCollector]; - if (tempVirtualizationPropertiesCollectorArray.length !== 0) - setChoroplethProperties([...tempVirtualizationPropertiesCollectorArray, ...(resources || [])]); - }; - - let setBoundary = {}; - let setFilter = {}; - const virtualizationPropertiesCollector = new Set(); - const filterPropertiesCollector = new Set(); - const filterPropertieNameCollector = new Set(); - const resources = state?.Resources?.find((item) => item.campaignType === campaignType)?.data; - const hypothesisAssumptionsList = microplanData?.hypothesis; - const formulaConfiguration = microplanData?.ruleEngine; - - let dataAvailabilityCheck = initializeDataAvailability(microplanData); - if (!dataAvailabilityCheck) return setToast({ state: "error", message: t("MAPPING_NO_DATA_TO_SHOW") }); - - const files = _.cloneDeep(microplanData.upload); - for (const fileData of files) { - if (!checkFileActivity(fileData) || !checkFileSection(fileData, filterDataOrigin)) { - dataAvailabilityCheck = "false"; - continue; - } - - if (!fileData?.fileType || !fileData?.section) continue; - - const schema = getFileValidationSchema(campaignType, fileData, validationSchemas); - dataAvailabilityCheck = handleFileDataError(dataAvailabilityCheck, fileData); - - const { latLngColumns, filterProperty } = processFileData( - fileData, - schema, - filterDataOrigin, - virtualizationPropertiesCollector, - filterPropertiesCollector, - filterPropertieNameCollector, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - t - ); - - if (fileData?.data && Object.keys(fileData?.data).length > 0) { - switch (fileData?.fileType) { - case EXCEL: - const { dataAvailabilityCheck: excelDataAvailabilityCheck, hasLocationData, convertedData } = processExcelFile( - fileData, - latLngColumns, - resources, - formulaConfiguration, - hypothesisAssumptionsList, - schema, - t - ); - dataAvailabilityCheck = excelDataAvailabilityCheck; - if (hasLocationData) updateFilterPropertiesCollector(fileData, filterProperty, filterPropertiesCollector); - const { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } = processHierarchyAndData(hierarchy, convertedData); - if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData.section)) - setBoundary = { ...setBoundary, [fileData.section]: { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } }; - else if (filterDataOrigin?.layerDataOrigin?.includes(fileData.section)) - setFilter = { ...setFilter, [fileData.section]: { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } }; - break; - case GEOJSON: - case SHAPEFILE: - const { dataAvailabilityCheck: geoJsonDataAvailabilityCheck, dataWithResources } = processGeoJsonFile( - fileData, - filterProperty, - resources, - formulaConfiguration, - hypothesisAssumptionsList, - t - ); - dataAvailabilityCheck = geoJsonDataAvailabilityCheck; - const { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData } = processHierarchyAndData(hierarchy, [ - dataWithResources, - ]); - if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData.section)) - setBoundary = { - ...setBoundary, - [fileData.section]: { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData }, - }; - else if (filterDataOrigin?.layerDataOrigin?.includes(fileData.section)) - setFilter = { ...setFilter, [fileData.section]: { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData } }; - break; - default: - break; - } - } - } - - const combineList = [...(filterDataOrigin?.boundriesDataOrigin || []), ...(filterDataOrigin?.layerDataOrigin || [])]; - dataAvailabilityCheck = setAvailabilityAndToastMessages(dataAvailabilityCheck, combineList, files, setToast, t); - - setFinalDataAndProperties( - dataAvailabilityCheck, - setBoundary, - setFilter, - setBoundaryData, - setFilterData, - setFilterProperties, - setFilterSelections, - setFilterPropertyNames, - filterPropertiesCollector, - filterPropertieNameCollector, - virtualizationPropertiesCollector, - setChoroplethProperties, - resources - ); -}; - -//prepare geojson to show on the map -export const prepareGeojson = (boundaryData, selection, style = {}) => { - if (!boundaryData || Object.keys(boundaryData).length === 0) return []; - let geojsonRawFeatures = []; - if (selection === "ALL") { - for (let data of Object.values(boundaryData)) { - const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); - if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; - } - } else if (Array.isArray(selection)) { - for (let data of Object.values(boundaryData)) { - const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); - if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; - } - } - - return geojsonRawFeatures.filter(Boolean); -}; -export const fetchFeatures = (data, parameter = "ALL", outputList = [], addOn = {}) => { - let tempStorage = []; - if (parameter === "ALL") { - // outputList(Object.values(data).flatMap(item=>item?.data?.feature)) - for (let [entityKey, entityValue] of Object.entries(data)) { - if (entityValue?.data?.feature) { - let feature = entityValue.data.feature; - feature.properties["name"] = entityKey; - feature.properties["addOn"] = addOn; - if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - else tempStorage = [...tempStorage, feature]; - } else { - tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - } - } - return tempStorage; - } - if (Array.isArray(parameter)) { - for (let [entityKey, entityValue] of Object.entries(data)) { - if (parameter.includes(entityKey) && entityValue && entityValue.data && entityValue.data.feature) { - let feature = entityValue.data.feature; - feature.properties["name"] = entityKey; - feature.properties["addOn"] = addOn; - if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - else tempStorage = [...tempStorage, feature]; - } - if (entityValue?.children) tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - } - return tempStorage; - } -}; - -export const addChoroplethProperties = (geojson, choroplethProperty, filteredSelection) => { - // Calculate min and max values of the property - const values = geojson.map((feature) => feature.properties[choroplethProperty]).filter((item) => !!item || item === 0) || []; - if (!values || values.length === 0) return []; - const convertedValues = values.map((item) => (!isNaN(item) ? item : 0)); - const minValue = Math.min(...convertedValues); - const maxValue = Math.max(...convertedValues); - - // Create a new geojson object - const newGeojson = geojson.map((feature) => { - const newFeature = { ...feature, properties: { ...feature.properties, addOn: { ...feature.properties.addOn } } }; - let color; - - if (choroplethProperty) { - color = interpolateColor(newFeature.properties[choroplethProperty], minValue, maxValue, MapChoroplethGradientColors); - } - - newFeature.properties.addOn.fillColor = color; - newFeature.properties.addOn.color = "rgba(0, 0, 0, 1)"; - if (!filteredSelection || filteredSelection.length === 0 || filteredSelection.includes(newFeature.properties.name)) { - newFeature.properties.addOn.fillOpacity = 1; - } else { - newFeature.properties.addOn.fillOpacity = 0.4; - newFeature.properties.addOn.opacity = 0.7; - } - - return newFeature; - }); - return newGeojson; -}; - -/** - * filterGeojsons : json - * filterSelection : array - * MapFilters : - */ -export const addFilterProperties = (filterGeojsons, filterSelections, filterPropertyNames, iconMapping) => { - try { - if (!filterGeojsons || !iconMapping || !filterSelections) return []; - let newFilterGeojson = []; - filterGeojsons.forEach((item) => { - if (filterPropertyNames && filterPropertyNames.length !== 0 && item.properties) { - let icon; - filterPropertyNames.forEach((name) => { - if (item.properties[name]) { - let temp = item.properties[name]; - if (!filterSelections.includes(temp)) return; - temp = iconMapping?.find((e) => e?.name == temp)?.icon?.marker; - let DynamicIcon = IconCollection?.[temp]; - if (typeof DynamicIcon === "function") { - icon = L.divIcon({ - className: "custom-svg-icon", - html: DynamicIcon({}), - iconAnchor: [25, 50], - }); - newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); - } else { - icon = DefaultMapMarker({}); - newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); - } - } - }); - } - return item; - }); - return newFilterGeojson; - } catch (error) { - console.error(error.message); - } -}; - -/** - * map: map - * geojson: geojson - * t: translator - */ - -export const addGeojsonToMap = (map, geojson, t) => { - try { - if (!map || !geojson) return false; - const geojsonLayer = L.geoJSON(geojson, { - style: (feature) => { - if (Object.keys(feature.properties.addOn).length !== 0) { - return feature.properties.addOn; - } - return { - weight: 2, - opacity: 1, - color: "rgba(176, 176, 176, 1)", - fillColor: "rgb(0,0,0,0)", - // fillColor: choroplethProperty ? color : "rgb(0,0,0,0)", - fillOpacity: 0, - // fillOpacity: choroplethProperty ? (feature?.properties?.style?.fillOpacity ? feature.properties.style.fillOpacity : 0.7) : 0, - }; - }, - pointToLayer: (feature, latlng) => { - if (feature.properties.addOn.icon) { - let icon = feature.properties.addOn.icon; - if (icon) { - return L.marker(latlng, { - icon: icon, - }); - } - } - return L.marker(latlng, { - icon: MapMarker(feature.properties.addOn), - }); - }, - onEachFeature: (feature, layer) => { - let popupContent; - popupContent = "
"; - popupContent += "
"; - popupContent += `
${feature.properties["name"]}
`; - for (let prop in feature.properties) { - if (prop !== "name" && prop !== "addOn" && prop !== "feature") { - let data = feature.properties[prop] ? feature.properties[prop] : t("NO_DATA"); - popupContent += - ""; - } - } - popupContent += "
" + - t(prop) + - "" + - data + - "
"; - layer.bindPopup(popupContent, { - minWidth: "28rem", - padding: "0", - }); - // Adjust map here when pop up closes - layer.on("popupclose", () => { - map.fitBounds(geojsonLayer.getBounds()); - }); - layer.on({ - mouseover: (e) => { - const layer = e.target; - if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { - return; - } - if (layer.setStyle) - layer.setStyle({ - weight: 2.7, - opacity: 1, - color: "rgba(255, 255, 255, 1)", - }); - // layer.openPopup(); - }, - mouseout: (e) => { - const layer = e.target; - if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { - return; - } - if (layer.setStyle) { - if (layer.feature.properties.addOn && Object.keys(layer.feature.properties.addOn).length !== 0) - layer.setStyle({ - ...layer.feature.properties.addOn, - }); - else - layer.setStyle({ - weight: 2, - color: "rgba(176, 176, 176, 1)", - }); - } - // layer.closePopup(); - }, - }); - }, - }); - geojsonLayer.addTo(map); - return geojsonLayer; - } catch (error) { - console.error(error.message); - } -}; - -export const interpolateColor = (value, minValue, maxValue, colors) => { - // Handle case where min and max values are the same - if (minValue === maxValue) { - // Return a default color or handle the case as needed - return colors[0].color; - } - - // Normalize the value to a percentage between 0 and 100 - const percent = !isNaN(value) ? ((value - minValue) / (maxValue - minValue)) * 100 : 0; - // Find the two colors to interpolate between - let lowerColor, upperColor; - for (let i = 0; i < colors.length - 1; i++) { - if (!isNaN(percent) && percent >= colors[i].percent && percent <= colors[i + 1].percent) { - lowerColor = colors[i]; - upperColor = colors[i + 1]; - break; - } - } - // Interpolate between the two colors - const t = (percent - lowerColor.percent) / (upperColor.percent - lowerColor.percent); - return chroma.mix(lowerColor.color, upperColor.color, t, "lab").hex(); -}; - -// Find bounds for multiple geojson together -export const findBounds = (data, buffer = 0.1) => { - if (!Array.isArray(data) || data.length === 0) { - return null; - } - - // Initialize variables to store bounds - var minLat = Number.MAX_VALUE; - var maxLat = -Number.MAX_VALUE; - var minLng = Number.MAX_VALUE; - var maxLng = -Number.MAX_VALUE; - - // Iterate through the data to find bounds - data.forEach(function (feature) { - if (!feature || !feature.geometry || !feature.geometry.type || !feature.geometry.coordinates) { - return null; - } - - var coords = feature.geometry.coordinates; - var geometryType = feature.geometry.type; - - switch (geometryType) { - case "Point": - var coord = coords; - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - break; - case "MultiPoint": - coords.forEach(function (coord) { - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - }); - break; - case "LineString": - case "MultiLineString": - case "Polygon": - case "MultiPolygon": - coords.forEach(function (polygons) { - if ((geometryType === "Polygon" || geometryType === "MultiPolygon") && Array.isArray(polygons[0][0])) { - polygons.forEach(function (coordinates) { - coordinates.forEach(function (coord) { - if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { - return null; - } - - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - }); - }); - } else { - polygons.forEach(function (coord) { - if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { - return null; - } - - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - }); - } - }); - break; - default: - return null; - } - }); - - // Check if valid bounds found - if (minLat === Number.MAX_VALUE || maxLat === -Number.MAX_VALUE || minLng === Number.MAX_VALUE || maxLng === -Number.MAX_VALUE) { - return null; - } - // Apply buffer to bounds - minLat -= buffer; - maxLat += buffer; - minLng -= buffer; - maxLng += buffer; - - // Set bounds for the Leaflet map - var bounds = [ - [minLat, minLng], - [maxLat, maxLng], - ]; - - return bounds; -}; - -export const filterBoundarySelection = (boundaryData, boundarySelections) => { - if (Object.keys(boundaryData).length === 0 || Object.keys(boundarySelections).length === 0) return []; - let selectionList = []; - Object.values(boundarySelections).forEach((item) => (selectionList = [...selectionList, ...item.map((e) => e.name)])); - let childrenList = []; - const set1 = new Set(selectionList); - selectionList = selectionList.filter((item) => { - const children = findChildren([item], Object.values(boundaryData)?.[0]?.hierarchicalData); - if (children) { - let childrenKeyList = getAllKeys(children); - childrenList = [...childrenList, ...childrenKeyList]; - const nonePresent = childrenKeyList.every((item) => !set1.has(item)); - const allPresent = childrenKeyList.every((item) => set1.has(item)); - return nonePresent ? true : allPresent ? true : false; - } - return true; - }); - return { filteredSelection: selectionList, childrenList }; -}; - -// Recursive function to extract all keys -export const getAllKeys = (obj, keys = []) => { - for (let [key, value] of Object.entries(obj)) { - keys.push(key); - if (value.children) { - getAllKeys(value.children, keys); - } - } - return keys; -}; - -// Remove all layers from the map -export const removeAllLayers = (map, layer) => { - if (!map) return; - layer.forEach((layer) => { - map.removeLayer(layer); - }); -}; -// Map-Marker -export const MapMarker = (style = {}) => { - return L.divIcon({ - className: "custom-svg-icon", - html: PopulationSvg(style), - iconAnchor: [25, 50], - }); -}; -export const DefaultMapMarker = (style = {}) => { - return L.divIcon({ - className: "custom-svg-icon", - html: IconCollection.DefaultMapMarkerSvg(style), - iconAnchor: [25, 50], - }); -}; - -export const disableMapInteractions = (map) => { - if (!map) return; - map.dragging.disable(); - map.scrollWheelZoom.disable(); - map.touchZoom.disable(); - map.doubleClickZoom.disable(); - map.boxZoom.disable(); - map.keyboard.disable(); -}; - -export const enableMapInteractions = (map) => { - if (!map) return; - map.dragging.enable(); - map.scrollWheelZoom.enable(); - map.touchZoom.enable(); - map.doubleClickZoom.enable(); - map.boxZoom.enable(); - map.keyboard.enable(); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js deleted file mode 100644 index ff5cd55208f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js +++ /dev/null @@ -1,413 +0,0 @@ -import { EXCEL, GEOJSON, SHAPEFILE, commonColumn } from "../configs/constants"; - -export const calculateAggregateValue = (aggregateName, dataToShow) => { - if (!aggregateName || !dataToShow || dataToShow.length === 0) return; - let aggregateNameList = aggregateName; - if (typeof aggregateName !== "object") aggregateNameList = { name: aggregateName, entities: [aggregateName] }; - let aggregateData = 0; - if (aggregateNameList) - for (const item of aggregateNameList.entities) { - const columnIndex = dataToShow?.[0].indexOf(item); - dataToShow.slice(1).forEach((e) => { - if (e?.[columnIndex]) aggregateData = aggregateData + Number(e[columnIndex]); - }); - } - return aggregateData; -}; - -export const fetchMicroplanData = (microplanData, campaignType, validationSchemas) => { - if (!microplanData) return []; - - let combinesDataList = []; - // Check if microplanData and its upload property exist - if (microplanData?.upload) { - let files = microplanData?.upload; - // Loop through each file in the microplan upload - for (let fileData of files) { - const schema = getSchema(campaignType, fileData.fileType, fileData.templateIdentifier, validationSchemas); - - // Check if the file is not part of boundary or layer data origins - if (!fileData.active || !fileData.fileType || !fileData?.section) continue; // Skip files with errors or missing properties - - // Check if file contains latitude and longitude columns - if (fileData?.data) { - // Check file type and update data availability accordingly - switch (fileData?.fileType) { - case EXCEL: { - // extract dada - const mergedData = schema?.template?.hierarchyLevelWiseSheets ? Object.values(fileData?.data).flat() : Object.values(fileData?.data)?.[0]; - - let commonColumnIndex = mergedData?.[0]?.indexOf(commonColumn); - - let uniqueEntries; - if (commonColumnIndex !== undefined) - uniqueEntries = schema?.template?.hierarchyLevelWiseSheets - ? Array.from(new Map(mergedData.map((entry) => [entry[commonColumnIndex], entry])).values()) - : mergedData; - if (uniqueEntries) combinesDataList.push(uniqueEntries); - break; - } - case GEOJSON: - case SHAPEFILE: { - // Extract keys from the first feature's properties - let keys = Object.keys(fileData?.data.features[0].properties); - - // Extract corresponding values for each feature - const values = fileData?.data?.features.map((feature) => { - // list with features added to it - const temp = keys.map((key) => { - // if (feature.properties[key] === "") { - // return null; - // } - return feature.properties[key]; - }); - return temp; - }); - - let data = [keys, ...values]; - combinesDataList.push(data); - } - } - } - } - } - return combinesDataList; -}; - -// get schema for validation -export const getSchema = (campaignType, type, section, schemas) => { - return schemas.find((schema) => - schema.campaignType - ? schema.campaignType === campaignType && schema.type === type && schema.section === section - : schema.type === type && schema.section === section - ); -}; - -export const fetchMicroplanPreviewData = (campaignType, microplanData, validationSchemas, hierarchy) => { - try { - const filteredSchemaColumns = getFilteredSchemaColumnsList(campaignType, microplanData, validationSchemas, hierarchy); - const fetchedData = fetchMicroplanData(microplanData, campaignType, validationSchemas); - const dataAfterJoins = performDataJoins(fetchedData, filteredSchemaColumns); - return dataAfterJoins; - } catch (error) { - console.error("Error in fetch microplan data: ", error.message); - } -}; - -const getFilteredSchemaColumnsList = (campaignType, microplanData, validationSchemas, hierarchy) => { - let filteredSchemaColumns = getRequiredColumnsFromSchema(campaignType, microplanData, validationSchemas) || []; - if (hierarchy) { - filteredSchemaColumns = [...hierarchy, commonColumn, ...filteredSchemaColumns.filter((e) => e !== commonColumn)]; - } - return filteredSchemaColumns; -}; - -const performDataJoins = (fetchedData, filteredSchemaColumns) => { - return fetchedData.reduce((accumulator, currentData, index) => { - if (index === 0) { - return innerJoinLists(currentData, null, commonColumn, filteredSchemaColumns); - } - return innerJoinLists(accumulator, currentData, commonColumn, filteredSchemaColumns); - }, null); -}; - -export const filterObjects = (arr1, arr2) => { - if (!arr1 || !arr2) return []; - // Create a new array to store the filtered objects - let filteredArray = []; - - // Iterate through the first array - arr1.forEach((obj1) => { - // Find the corresponding object in the second array - let obj2 = _.cloneDeep(arr2.find((item) => item.key === obj1.key)); - - // If the object with the same key is found in the second array and their values are the same - if (obj2 && obj1.value !== obj2.value) { - // Push the object to the filtered array - obj1.oldValue = obj2.value; - filteredArray.push(obj1); - } - }); - - return filteredArray; -}; - -export const useHypothesis = (tempHypothesisList, hypothesisAssumptionsList) => { - // Handles the change in hypothesis value - const valueChangeHandler = (e, setTempHypothesisList, boundarySelections, setToast, t) => { - // Checks it the boundary filters at at root level ( given constraints ) - if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) - return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); - - // validating user input - if (e?.newValue.includes("+") || e?.newValue.includes("e")) return; - if ((e?.newValue < 0 || e.newValue > 10000000000) && e?.newValue !== "") return; - let value; - const decimalIndex = e.newValue.indexOf("."); - if (decimalIndex !== -1) { - const numDecimals = e.newValue.length - decimalIndex - 1; - if (numDecimals <= 2) { - value = e.newValue; - } else if (numDecimals > 2) { - value = e.newValue.substring(0, decimalIndex + 3); - } - } else value = parseFloat(e.newValue); - value = !isNaN(value) ? value : ""; - - // update the state with user input - let newhypothesisEntityIndex = hypothesisAssumptionsList.findIndex((item) => item?.id === e?.item?.id); - let unprocessedHypothesisList = _.cloneDeep(tempHypothesisList); - if (newhypothesisEntityIndex !== -1) unprocessedHypothesisList[newhypothesisEntityIndex].value = value; - setTempHypothesisList(unprocessedHypothesisList); - }; - - return { - valueChangeHandler, - }; -}; - -const validateRequestBody = (body, state, campaignType, setLoaderActivation, setToast, setCheckDataCompletion, navigationEvent, t) => { - if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) { - setLoaderActivation(false); - if (navigationEvent.name === "next") { - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - }); - setCheckDataCompletion("false"); - } else { - setCheckDataCompletion("perform-action"); - } - return false; - } - return true; -}; - -const handleApiSuccess = (data, updateData, setLoaderActivation, setMicroplanData, status) => { - updateData(); - setLoaderActivation(false); - setMicroplanData((previous) => ({ ...previous, microplanStatus: status })); -}; - -const handleApiError = (error, variables, setLoaderActivation, setToast, status, cancleNavigation, updateData, t) => { - setLoaderActivation(false); - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - }); - if (status === "GENERATED") { - cancleNavigation(); - } else { - updateData(); - } -}; - -const constructRequestBody = (microplanData, operatorsObject, MicroplanName, campaignId, status) => { - const body = Digit.Utils.microplan.mapDataForApi(microplanData, operatorsObject, MicroplanName, campaignId, status); - body.PlanConfiguration["id"] = microplanData?.planConfigurationId; - body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; - return body; -}; - -export const updateHyothesisAPICall = async ( - microplanData, - setMicroplanData, - operatorsObject, - MicroplanName, - campaignId, - UpdateMutate, - setToast, - updateData, - setLoaderActivation, - status, - cancleNavigation, - state, - campaignType, - navigationEvent, - setCheckDataCompletion, - t -) => { - try { - const body = constructRequestBody(microplanData, operatorsObject, MicroplanName, campaignId, status); - const isValid = validateRequestBody(body, state, campaignType, setLoaderActivation, setToast, setCheckDataCompletion, navigationEvent, t); - if (!isValid) return; - - await UpdateMutate(body, { - onSuccess: (data) => handleApiSuccess(data, updateData, setLoaderActivation, setMicroplanData, status), - onError: (error, variables) => handleApiError(error, variables, setLoaderActivation, setToast, status, cancleNavigation, updateData, t), - }); - } catch (error) { - setLoaderActivation(false); - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - }); - } -}; - -// get schema for validation -export const getRequiredColumnsFromSchema = (campaignType, microplanData, schemas) => { - if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; - const sortData = []; - if (microplanData?.upload) { - for (const value of microplanData.upload) { - if (value.active && value?.error === null) { - sortData.push({ section: value.section, fileType: value?.fileType }); - } - } - } - const filteredSchemas = - schemas?.filter((schema) => { - if (schema.campaignType) { - return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); - } - return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); - }) || []; - - let finalData = []; - let tempdata; - - tempdata = filteredSchemas - ?.flatMap((item) => - Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRuleConfigureInputs && value?.toShowInMicroplanPreview) { - acc.push(key); - } - return acc; - }, []) - ) - .filter((item) => !!item); - finalData = [...finalData, ...tempdata]; - - tempdata = filteredSchemas - ?.flatMap((item) => - Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.toShowInMicroplanPreview) acc.push(key); - return acc; - }, []) - ) - .filter((item) => !!item); - finalData = [...finalData, ...tempdata]; - return [...new Set(finalData)]; -}; - -/** - * Combines two datasets based on a common column, duplicating rows from data1 for each matching row in data2. - * The final dataset's columns and their order are determined by listOfColumnsNeededInFinalData. - * If data2 is not provided, rows from data1 are included with null values for missing columns. - */ -export const innerJoinLists = (data1, data2, commonColumnName, listOfColumnsNeededInFinalData) => { - // Error handling: Check if data1 array is provided - if (!Array.isArray(data1)) { - throw new Error("The first data input must be an array."); - } - - // Error handling: Check if common column name is provided - if (typeof commonColumnName !== "string") { - throw new Error("Common column name must be a string."); - } - - // Error handling: Check if listOfColumnsNeededInFinalData is provided and is an array - if (!Array.isArray(listOfColumnsNeededInFinalData)) { - throw new Error("listOfColumnsNeededInFinalData must be an array."); - } - - // Find the index of the common column in the first dataset - const commonColumnIndex1 = data1[0].indexOf(commonColumnName); - - // Error handling: Check if common column exists in the first dataset - if (commonColumnIndex1 === -1) { - throw new Error(`Common column "${commonColumnName}" not found in the first dataset.`); - } - - let commonColumnIndex2 = -1; - const data2Map = new Map(); - if (data2) { - // Find the index of the common column in the second dataset - commonColumnIndex2 = data2[0].indexOf(commonColumnName); - - // Error handling: Check if common column exists in the second dataset - if (commonColumnIndex2 === -1) { - throw new Error(`Common column "${commonColumnName}" not found in the second dataset.`); - } - - // Create a map for the second dataset for quick lookup by the common column value - for (let i = 1; i < data2.length; i++) { - const row = data2[i]; - const commonValue = row[commonColumnIndex2]; - if (!data2Map.has(commonValue)) { - data2Map.set(commonValue, []); - } - data2Map.get(commonValue).push(row); - } - } - - // Determine the headers for the final combined dataset based on listOfColumnsNeededInFinalData - const combinedHeaders = listOfColumnsNeededInFinalData.filter((header) => data1[0].includes(header) || data2?.[0].includes(header)); - - // Combine rows - const combinedData = [combinedHeaders]; - const addedCommonValues = new Set(); - for (let i = 1; i < data1.length; i++) { - const row1 = data1[i]; - const commonValue = row1[commonColumnIndex1]; - const rows2 = data2 ? data2Map.get(commonValue) || [[null]] : [[null]]; // Handle missing common values with a placeholder array of null - - // Check if rows2 is the placeholder array - const isPlaceholderArray = rows2.length === 1 && rows2[0].every((value) => value === null); - - // Create combined rows for each row in data2 - if (isPlaceholderArray) { - // If no corresponding row found in data2, use row from data1 with null values for missing columns - const combinedRow = combinedHeaders.map((header) => { - const index1 = data1[0].indexOf(header); - return index1 !== -1 ? row1[index1] : null; - }); - combinedData.push(combinedRow); - } else { - // If corresponding rows found in data2, combine each row from data2 with row from data1 - rows2.forEach((row2) => { - const combinedRow = combinedHeaders.map((header) => { - const index1 = data1[0].indexOf(header); - const index2 = data2 ? data2[0].indexOf(header) : -1; - return index1 !== -1 ? row1[index1] : index2 !== -1 ? row2[index2] : null; - }); - combinedData.push(combinedRow); - }); - } - addedCommonValues.add(commonValue); - } - // Add rows from data2 that do not have a matching row in data1 - if (data2) { - for (let i = 1; i < data2.length; i++) { - const row2 = data2[i]; - const commonValue = row2[commonColumnIndex2]; - if (!addedCommonValues.has(commonValue)) { - const combinedRow = combinedHeaders.map((header) => { - // const index1 = data1[0].indexOf(header); - const index2 = data2[0].indexOf(header); - return index2 !== -1 ? row2[index2] : null; - }); - combinedData.push(combinedRow); - } - } - } - - return combinedData; -}; - -// function to filter the microplan data with respect to the hierarchy selected by the user -export const filterMicroplanDataToShowWithHierarchySelection = (data, selections, hierarchy, hierarchyIndex = 0) => { - if (!selections || selections?.length === 0) return data; - if (hierarchyIndex >= hierarchy?.length) return data; - const filteredHirarchyLevelList = selections?.[hierarchy?.[hierarchyIndex]]?.map((item) => item?.name); - if (!filteredHirarchyLevelList || filteredHirarchyLevelList?.length === 0) return data; - const columnDataIndexForHierarchyLevel = data?.[0]?.indexOf(hierarchy?.[hierarchyIndex]); - if (columnDataIndexForHierarchyLevel === -1) return data; - const levelFilteredData = data.filter((item, index) => { - if (index === 0) return true; - if (item?.[columnDataIndexForHierarchyLevel] && filteredHirarchyLevelList.includes(item?.[columnDataIndexForHierarchyLevel])) return true; - return false; - }); - return filterMicroplanDataToShowWithHierarchySelection(levelFilteredData, selections, hierarchy, hierarchyIndex + 1); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js deleted file mode 100644 index 09e24a4658e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js +++ /dev/null @@ -1,351 +0,0 @@ -export const processHierarchyAndData = (hierarchy, allData) => { - const hierarchyLists = {}; - let hierarchicalData = {}; - try { - // Process hierarchy - hierarchy.forEach((item) => { - hierarchyLists[item.boundaryType] = []; - }); - - // Process all sets of data - allData.forEach((data) => { - const dataHierarchicalData = {}; - - // Process data for this set - data.slice(1).forEach((row) => { - // Exclude the header row - let currentNode = dataHierarchicalData; - let parent = null; - hierarchy.forEach((item, index) => { - const boundaryType = item.boundaryType; - const dataIndex = data?.[0].indexOf(boundaryType); - if (dataIndex === -1) return; - const cellValue = row[dataIndex]; - if (!cellValue) return; - // Populate hierarchy lists - if (!hierarchyLists[boundaryType].includes(cellValue) && cellValue !== null && cellValue !== "" && cellValue !== undefined) { - hierarchyLists[boundaryType].push(cellValue); - } - - // Populate hierarchical data - if (!currentNode[cellValue]) { - currentNode[cellValue] = { - name: cellValue, - boundaryType: boundaryType, - children: {}, - data: null, - }; - } - - // Assign row data to the correct hierarchical level - if (cellValue) { - if (index === hierarchy.length - 1) { - currentNode[cellValue].data = createDataObject(data[0], row); - } else if (index + 1 < hierarchy.length) { - let nextHierarchyList = hierarchy.slice(index + 1); - let check = true; - nextHierarchyList.forEach((e) => { - const boundaryType = e.boundaryType; - const dataIndex = data?.[0].indexOf(boundaryType); - if (dataIndex === -1) return; - check = check && !row[dataIndex]; - }); - if (check) currentNode[cellValue].data = createDataObject(data[0], row); - } - } - currentNode = currentNode[cellValue].children; - }); - }); - - // Merge dataHierarchicalData into hierarchicalData - hierarchicalData = mergeHierarchicalData(hierarchicalData, dataHierarchicalData); - }); - - // Remove null element from children of each province - Object.values(hierarchicalData).forEach((country) => { - if (country.children[null]) { - country.data = country.children[null].data; - country.children[null] = undefined; - } - }); - } catch (error) { - console.error("Error in processing hierarchy and uploaded data: ", error.message); - // Return empty objects in case of error - return { hierarchyLists: {}, hierarchicalData: {} }; - } - - return { hierarchyLists, hierarchicalData }; -}; - -// Function to merge two hierarchical data objects -const mergeHierarchicalData = (data1, data2) => { - for (const [key, value] of Object.entries(data2)) { - if (!data1[key]) { - if (!value.data) value.data = {}; - data1[key] = value || {}; - } else { - data1[key].data = value.data; // Merge data - mergeHierarchicalData(data1[key].children, value.children); // Recursively merge children - } - if (data1[key].data?.feature) { - const { feature, ...temp } = value.data ? _.cloneDeep(value.data) : {}; - data1[key].data.feature.properties = { ...data1[key].data?.feature?.properties, ...temp }; - } - } - return data1; -}; - -// Function to create a data object with key-value pairs from headers and row data -const createDataObject = (headers, row) => { - const dataObject = {}; - headers.forEach((header, index) => { - dataObject[header] = row[index]; - }); - return dataObject; -}; - -// Find parent in hierarchy -export const findParent = (name, hierarchy, parent, accumulator = []) => { - if (!name || !hierarchy) return null; - for (let key in hierarchy) { - if (hierarchy[key]?.name == name) { - accumulator.push(parent); - } - if (hierarchy[key]?.children) { - let response = findParent(name, hierarchy[key]?.children, hierarchy[key], accumulator); - if (response) - response.forEach((item) => { - if (!accumulator.includes(item)) { - accumulator.push(item); - } - }); - } else { - return accumulator; - } - } - return accumulator; -}; - -/** - * - * @param {Array of parents} parents - * @param {hierarchycal Object data} hierarchy - * @returns An Array containing all the cummulative children - */ -export const findChildren = (parents, hierarchy) => { - const hierarchyTraveller = (parents, hierarchy, accumulator = {}) => { - let tempData = []; - if (accumulator && Object.keys(accumulator).length !== 0) - tempData = { - ...accumulator, - ...hierarchy.reduce((data, item) => { - if (parents.includes(item?.name) && item?.children) { - for (const key in item.children) { - if (!data[key]) { - data[key] = item.children[key]; - } - } - } - return data; - }, {}), - }; - else - tempData = hierarchy.reduce((data, item) => { - if (parents.includes(item?.name) && item?.children) { - for (const key in item.children) { - if (!data[key]) { - data[key] = item.children[key]; - } - } - } - return data; - }, {}); - for (let parent of hierarchy) { - if (parent?.children) tempData = hierarchyTraveller(parents, Object.values(parent?.children), tempData); - } - return tempData; - }; - return hierarchyTraveller(parents, Object.values(hierarchy), {}); -}; - -// Fetched data from tree -export const fetchDropdownValues = (boundaryData, hierarchy, boundarySelections, changedBoundaryType) => { - if ( - !hierarchy || - !boundaryData || - !boundarySelections || - hierarchy.length === 0 || - Object.keys(hierarchy).length === 0 || - Object.keys(boundaryData).length === 0 - ) - return []; - let TempHierarchy = _.cloneDeep(hierarchy); - if (!boundarySelections || Object.values(boundarySelections)?.every((item) => item?.length === 0)) { - for (let i in TempHierarchy) { - if (i === "0") { - TempHierarchy[0].dropDownOptions = findByBoundaryType( - TempHierarchy?.[0]?.boundaryType, - Object.values(boundaryData)?.[0]?.hierarchicalData - ).map((data, index) => ({ - name: data, - code: data, - boundaryType: TempHierarchy?.[0]?.boundaryType, - parentBoundaryType: undefined, - })); - } else TempHierarchy[i].dropDownOptions = []; - } - } else { - const currentHierarchy = findCurrentFilteredHierarchy(Object.values(boundaryData)?.[0]?.hierarchicalData, boundarySelections, TempHierarchy); - let currentDropdownIndex = 0; - hierarchy.forEach((e, index) => { - if (e && e?.boundaryType == changedBoundaryType) { - // && boundarySelections && boundarySelections[e.boundaryType] && boundarySelections[e.boundaryType].length !== 0) { - currentDropdownIndex = index; - } - }); - Object.entries(boundarySelections)?.forEach(([key, value]) => { - let currentindex = hierarchy.findIndex((e) => e?.boundaryType === key); - if (currentDropdownIndex !== currentindex) return; - let childIndex = hierarchy.findIndex((e) => e?.parentBoundaryType === key); - if (childIndex == -1) return; - if (TempHierarchy?.[childIndex]) { - let newDropDownValuesForChild = []; - for (const element of value) { - let tempStore = Object.values(findChildren([element.name], currentHierarchy)).map((value) => ({ - name: value?.name, - code: value?.name, - parent: element, - boundaryType: TempHierarchy[childIndex]?.boundaryType, - parentBoundaryType: TempHierarchy[childIndex]?.parentBoundaryType, - })); - if (tempStore) newDropDownValuesForChild.push(...tempStore); - } - // if (TempHierarchy[childIndex].dropDownOptions) - // TempHierarchy[childIndex].dropDownOptions = [...TempHierarchy[childIndex].dropDownOptions, ...newDropDownValuesForChild]; - TempHierarchy[childIndex].dropDownOptions = newDropDownValuesForChild; - } - }); - } - return TempHierarchy; -}; - -const findByBoundaryType = (boundaryType, hierarchy) => { - for (let [key, value] of Object.entries(hierarchy)) { - if (value?.boundaryType === boundaryType) return Object.keys(hierarchy).filter(Boolean); - if (value?.children) return findByBoundaryType(boundaryType, value?.children); - return []; - } - return []; -}; - -// makes a tree with the boundary selections as there might be duplicates in different branches that are not yet selected -const findCurrentFilteredHierarchy = (hierarchyTree, boundarySelections, hierarchy) => { - const newtree = constructNewHierarchyTree(hierarchy, hierarchyTree, boundarySelections); - return newtree; -}; - -const constructNewHierarchyTree = (hierarchy, oldTree, boundarySelection, level = 0) => { - // let newTree = { ...oldTree }; // Initialize a new hierarchy tree - let newTree = {}; // Initialize a new hierarchy tree - if (!hierarchy?.[level]) return; - const levelName = hierarchy[level].boundaryType; - - // Get the selections for this level from the boundary selection object - const selections = boundarySelection[levelName] || []; - // If there are selections for this level - if (selections.length > 0) { - // Construct the new hierarchy tree based on selections - for (const selection of selections) { - const { name } = selection; - // If the selection exists in the existing hierarchy tree - if (oldTree[name]) { - // Add the selected division to the new hierarchy tree - newTree[name] = { ...oldTree[name] }; - // If there are children, recursively construct the children - if (oldTree[name].children) { - oldTree[name].children; - const nonNullObject = Object.entries(oldTree[name].children).reduce((acc, [key, value]) => { - if (value.name !== null) { - acc[key] = value; - } - return acc; - }, {}); - newTree[name].children = constructNewHierarchyTree(hierarchy, nonNullObject, boundarySelection, level + 1); - } - } - } - } else { - const nonNullObject = Object.entries(oldTree).reduce((acc, [key, value]) => { - if (value.name !== null) { - acc[key] = value; - } - return acc; - }, {}); - newTree = nonNullObject; - } - - return newTree; -}; - -// Recursively calculates aggregate values for numerical properties within the `data` objects of each node in a hierarchical tree structure. -// Updates the `properties` object within the `feature` object of each node with the aggregate values, if present. -export const calculateAggregateForTree = (tree) => { - try { - function calculateAggregate(node) { - if (!node.children || Object.keys(node.children).length === 0) { - // if the node has no children, return a new node with its own data - return { ...node, data: { ...node.data } }; - } - - // Recursively calculate aggregate values for each child - const newChildren = {}; - - for (const childKey in node.children) { - const child = node.children[childKey]; - const newChild = calculateAggregate(child); - newChildren[childKey] = newChild; - } - - // Aggregate numerical values dynamically - const aggregate = {}; - for (const childKey in newChildren) { - const child = newChildren[childKey]; - for (const prop in child.data) { - if (typeof child.data[prop] === "number") { - aggregate[prop] = (aggregate[prop] || 0) + child.data[prop]; - } - } - } - - // Create a new node with updated data - const newNode = { - ...node, - data: { ...node.data, ...aggregate }, - children: newChildren, - }; - - // Update properties in the feature object - if (newNode.data.feature) { - newNode.data.feature.properties = { ...newNode.data.feature.properties, ...aggregate }; - } - - return newNode; - } - - const newTree = {}; - - // Iterate over each node object - for (const nodeKey in tree) { - const node = tree[nodeKey]; - // Calculate aggregate values for the current node - const newNode = calculateAggregate(node); - // Add the updated node to the new tree - newTree[nodeKey] = newNode; - } - - return newTree; - } catch (error) { - console.error("Failed to calculate treenode aggregates"); - return {}; - } -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js deleted file mode 100644 index 129ec488b43..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js +++ /dev/null @@ -1,486 +0,0 @@ -import { Request } from "@egovernments/digit-ui-libraries"; -import { parseXlsxToJsonMultipleSheetsForSessionUtil } from "../utils/exceltojson"; -import JSZip from "jszip"; -import * as XLSX from "xlsx"; -import axios from "axios"; -import shp from "shpjs"; -import { EXCEL, GEOJSON, SHAPEFILE, ACCEPT_HEADERS, LOCALITY, commonColumn } from "../configs/constants"; -import { addBoundaryData, fetchBoundaryData, filterBoundaries } from "./createTemplate"; -import { handleExcelFile } from "./uploadUtils"; - -function handleExcelArrayBuffer(arrayBuffer, file) { - return new Promise((resolve, reject) => { - try { - // Read the response as an array buffer - // const arrayBuffer = response.arrayBuffer(); - - // Convert the array buffer to binary string - const data = new Uint8Array(arrayBuffer); - const binaryString = String.fromCharCode.apply(null, data); - - // Parse the binary string into a workbook - const workbook = XLSX.read(binaryString, { type: "binary" }); - - // Assuming there's only one sheet in the workbook - const sheetName = workbook.SheetNames[0]; - const sheet = workbook.Sheets[sheetName]; - - // Convert the sheet to JSON object - const jsonData = XLSX.utils.sheet_to_json(sheet); - - resolve(jsonData); - } catch (error) { - reject(error); - } - }); -} - -function shpToGeoJSON(shpBuffer, file) { - return new Promise((resolve, reject) => { - try { - shp(shpBuffer) - .then((geojson) => { - resolve({ jsonData: geojson, file }); - }) - .catch((error) => reject(error)); - } catch (error) { - reject(error); - } - }); -} - -function parseGeoJSONResponse(arrayBuffer, file) { - return new Promise((resolve, reject) => { - try { - const decoder = new TextDecoder("utf-8"); - const jsonString = decoder.decode(arrayBuffer); - const jsonData = JSON.parse(jsonString); - resolve({ jsonData, file }); - } catch (error) { - reject(error); - } - }); -} - -// Function to read blob data and parse it into JSON -function parseBlobToJSON(blob, file) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.onload = function (event) { - const data = new Uint8Array(event.target.result); - const workbook = XLSX.read(data, { type: "array" }); - const jsonData = {}; - - workbook.SheetNames.forEach((sheetName) => { - const sheetData = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]); - jsonData[sheetName] = sheetData; - }); - - resolve({ jsonData, file }); - }; - - reader.onerror = function () { - reject(new Error("Error reading the blob data")); - }; - - reader.readAsArrayBuffer(blob); - }); -} - -export const updateSessionUtils = { - computeSessionObject: async (row, state, additionalProps) => { - const sessionObj = {}; - const setCurrentPage = () => { - sessionObj.currentPage = { - id: 0, - name: "MICROPLAN_DETAILS", - component: "MicroplanDetails", - checkForCompleteness: true, - }; - }; - - //currently hardcoded - const setMicroplanStatus = () => { - sessionObj.status = { - MICROPLAN_DETAILS: true, - UPLOAD_DATA: true, - HYPOTHESIS: true, - FORMULA_CONFIGURATION: true, - }; - }; - - const setMicroplanDetails = () => { - if (row.name) { - sessionObj.microplanDetails = { - name: row?.name, - }; - } - }; - - const setMicroplanHypothesis = () => { - if (row.assumptions.length > 0) { - sessionObj.hypothesis = row.assumptions?.filter((item) => item?.active); - } - }; - - const sortRules = (rules) => { - // Step 1: Identify all unique rule outputs - const allOutputs = [...new Set(rules.map((rule) => rule.output))]; - - // Step 2: Build input-output relationships - const inputOutputMap = new Map(); // Map to store input -> output relationship - rules.forEach((rule) => { - const { input, output } = rule; - if (!inputOutputMap.has(input)) { - inputOutputMap.set(input, []); - } - inputOutputMap.get(input).push(output); - }); - - // Step 3: Sort the output list based on dependencies - const sortedOutputList = []; - const visited = new Set(); - - const dfs = (output) => { - if (!visited.has(output)) { - visited.add(output); - if (inputOutputMap.has(output)) { - inputOutputMap.get(output).forEach((input) => { - dfs(input); - }); - } - sortedOutputList.push(output); - } - }; - - // Sort outputs based on dependencies - allOutputs.forEach((output) => { - dfs(output); - }); - - // Reverse to get outputs in the correct order (outputs first) - sortedOutputList.reverse(); - - // Step 4: Arrange rules based on sorted output list - const sortedRules = []; - const ruleMap = new Map(rules.map((rule) => [rule.id, rule])); - - sortedOutputList.forEach((output) => { - rules - .filter((rule) => rule.output === output) - .forEach((rule) => { - sortedRules.push(rule); - }); - }); - - return sortedRules; - }; - - const setMicroplanRuleEngine = () => { - const rulesList = state.UIConfiguration?.filter((item) => item.name === "ruleConfigure")?.[0]?.ruleConfigureOperators; - let sortedRules = sortRules(row.operations); - if (row.operations.length > 0) { - sessionObj.ruleEngine = sortedRules?.map((item) => { - return { - ...item, - operator: rulesList.filter((rule) => rule.code === item.operator)?.[0]?.name, - }; - }); - } - }; - - const setDraftValues = () => { - sessionObj.planConfigurationId = row?.id; - sessionObj.auditDetails = row.auditDetails; - }; - - const fetchBoundaryDataWrapper = async (schemaData) => { - let boundaryDataAgainstBoundaryCode = {}; - // if (!schemaData?.doHierarchyCheckInUploadedData) { - try { - const rootBoundary = additionalProps.campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable - const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; - let boundaryData = sessionData.filteredBoundaries; - let filteredBoundaries; - if (!boundaryData) { - // Only fetch boundary data if not present in session storage - boundaryData = await fetchBoundaryData( - await Digit.ULBService.getCurrentTenantId(), - additionalProps.campaignData?.hierarchyType, - rootBoundary?.[0]?.code - ); - filteredBoundaries = await filterBoundaries(boundaryData, additionalProps.campaignData?.boundaries); - - // Update the session storage with the new filtered boundaries - Digit.SessionStorage.set("microplanHelperData", { - ...sessionData, - filteredBoundaries: filteredBoundaries, - }); - } else { - filteredBoundaries = boundaryData; - } - const xlsxData = addBoundaryData([], filteredBoundaries, additionalProps.campaignData?.hierarchyType)?.[0]?.data; - xlsxData.forEach((item, i) => { - if (i === 0) return; - let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn); - if (boundaryCodeIndex >= item.length) { - // If boundaryCodeIndex is out of bounds, return the item as is - boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(additionalProps.t); - } else { - // Otherwise, remove the element at boundaryCodeIndex - boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item - .slice(0, boundaryCodeIndex) - .concat(item.slice(boundaryCodeIndex + 1)) - .map(additionalProps.t); - } - }); - } catch (error) { - console.error(error?.message); - } - // } - return boundaryDataAgainstBoundaryCode; - }; - - const handleGeoJson = async (file, result, upload, translatedData, active, processedData, shapefileOrigin = false) => { - if (!file) { - console.error(`${shapefileOrigin ? "Shapefile" : "Geojson"} file is undefined`); - return upload; - } - - const { inputFileType, templateIdentifier, filestoreId, id: fileId } = file || {}; - let uploadObject = createUploadObject(templateIdentifier, inputFileType, fileId, filestoreId, shapefileOrigin ? ".zip" : ".geojson", active); - - const schema = findSchema(inputFileType, templateIdentifier, additionalProps?.campaignType); - if (!schema) { - console.error("Schema got undefined while handling geojson at handleGeoJson"); - return [...upload, uploadObject]; - } - - await handleGeoJsonSpecific(schema, uploadObject, templateIdentifier, result, translatedData, filestoreId, processedData); - upload.push(uploadObject); - return upload; - }; - - const handleExcel = (file, result, upload, translatedData, active) => { - if (!file) { - console.error("Excel file is undefined"); - return upload; - } - - const { inputFileType, templateIdentifier, filestoreId, id: fileId } = file || {}; - let uploadObject = createUploadObject(templateIdentifier, inputFileType, fileId, filestoreId, ".xlsx", active), - schema = findSchema(inputFileType, templateIdentifier, additionalProps.campaignType); - if (!schema) { - console.error("Schema got undefined while handling excel at handleExcel"); - return [...upload, uploadObject]; - } - - uploadObject.data = result; //resultAfterMapping?.tempFileDataToStore; - upload.push(uploadObject); - return upload; - }; - - const createUploadObject = (templateIdentifier, inputFileType, fileId, filestoreId, extension, active) => ({ - id: fileId, - templateIdentifier, - section: templateIdentifier, - fileName: `${templateIdentifier}${extension}`, - fileType: inputFileType, - file: null, - fileId: fileId, - filestoreId: filestoreId, - error: null, - resourceMapping: row?.resourceMapping?.filter((resourse) => resourse.filestoreId === filestoreId).map((item) => ({ ...item, filestoreId })), - data: {}, - active, - }); - - const findSchema = (inputFileType, templateIdentifier, campaignType) => { - return state?.Schemas?.find( - (schema) => - schema.type === inputFileType && schema.section === templateIdentifier && (!schema.campaignType || schema.campaignType === campaignType) - ); - }; - - const handleGeoJsonSpecific = async (schema, upload, templateIdentifier, result, translatedData, filestoreId, processedData) => { - let schemaKeys; - if (schema?.schema?.["Properties"]) { - schemaKeys = additionalProps.hierarchyData?.concat(Object.keys(schema.schema["Properties"])); - } - upload.data = result; - if (processedData) return; - const mappedToList = upload?.resourceMapping.map((item) => item.mappedTo); - let sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, upload?.resourceMapping); - const newFeatures = result["features"].map((item) => { - let newProperties = {}; - sortedSecondList - ?.filter((resourse) => resourse.filestoreId === filestoreId) - .forEach((e) => { - newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; - }); - item["properties"] = newProperties; - return item; - }); - upload.data.features = newFeatures; - if ( - additionalProps.hierarchyData?.every( - (item) => - !mappedToList.includes(`${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`) - ) - ) { - let boundaryDataAgainstBoundaryCode = await fetchBoundaryDataWrapper(schema); - upload.data.features.forEach((feature) => { - const boundaryCode = feature.properties.boundaryCode; - let additionalDetails = {}; - for (let i = 0; i < additionalProps.hierarchyData?.length; i++) { - if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { - additionalDetails[additionalProps.hierarchyData?.[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; - } else { - additionalDetails[additionalProps.hierarchyData?.[i]] = ""; - } - } - feature.properties = { ...additionalDetails, ...feature.properties }; - }); - } - }; - - const fetchFiles = async () => { - const files = row?.files; - if (!files || files.length === 0) { - return []; - } - - const promises = []; - let storedData = []; - for (const { filestoreId, inputFileType, templateIdentifier, id, active } of files) { - if (!active) continue; - const schemaData = findSchema(inputFileType, templateIdentifier, additionalProps?.campaignType); - if (!schemaData) { - console.error("Schema got undefined while handling geojson at handleGeoJson"); - return [...upload, uploadObject]; - } - const boundaryDataAgainstBoundaryCode = {}; - let fileData = { - filestoreId, - inputFileType, - templateIdentifier, - id, - }; - let dataInSsn = Digit.SessionStorage.get("microplanData")?.upload?.find((item) => item.active && item.id === id); - if (dataInSsn && dataInSsn.filestoreId === filestoreId) { - storedData.push({ file: fileData, jsonData: dataInSsn?.data, processedData: true, translatedData: false, active }); - } else { - const promiseToAttach = axios - .get("/filestore/v1/files/id", { - responseType: "arraybuffer", - headers: { - "Content-Type": "application/json", - Accept: ACCEPT_HEADERS[inputFileType], - "auth-token": Digit.UserService.getUser()?.["access_token"], - }, - params: { - tenantId: Digit.ULBService.getCurrentTenantId(), - fileStoreId: filestoreId, - }, - }) - .then(async (res) => { - if (inputFileType === EXCEL) { - try { - const file = new Blob([res.data], { type: ACCEPT_HEADERS[inputFileType] }); - const response = await handleExcelFile( - file, - schemaData, - additionalProps.hierarchyData.map( - (item) => `${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}` - ), - { id: inputFileType }, - boundaryDataAgainstBoundaryCode, - () => {}, - additionalProps.t, - additionalProps.campaignData, - additionalProps.readMeSheetName - ); - let fileData = { - filestoreId, - inputFileType, - templateIdentifier, - id, - }; - - return { jsonData: response.fileDataToStore, file: fileData, translatedData: true, active }; - } catch (error) { - console.error(error); - } - } else if (inputFileType === GEOJSON) { - let response = await parseGeoJSONResponse(res.data, { - filestoreId, - inputFileType, - templateIdentifier, - id, - }); - return { ...response, translatedData: true, active }; - } else if (inputFileType === SHAPEFILE) { - const geoJson = await shpToGeoJSON(res.data, { - filestoreId, - inputFileType, - templateIdentifier, - id, - }); - return { ...geoJson, translatedData: true, active }; - } - }); - promises.push(promiseToAttach); - } - } - - const resolvedPromises = await Promise.all(promises); - let result = storedData; - if (resolvedPromises) result = [...storedData, ...resolvedPromises]; - return result; - }; - const setMicroplanUpload = async (filesResponse) => { - //here based on files response set data in session - if (filesResponse.length === 0) { - return {}; - } - //populate this object based on the files and return - let upload = []; - - await filesResponse.forEach(async ({ jsonData, file, translatedData, active, processedData }, idx) => { - switch (file?.inputFileType) { - case "Shapefile": - upload = await handleGeoJson(file, jsonData, upload, translatedData, active, processedData, true); - break; - case "Excel": - upload = handleExcel(file, jsonData, upload, translatedData, active); - break; - case "GeoJSON": - upload = await handleGeoJson(file, jsonData, upload, translatedData, active, processedData); - break; - default: - break; - } - }); - //here basically parse the files data from filestore parse it and populate upload object based on file type -> excel,shape,geojson - return upload; - }; - - try { - setCurrentPage(); - setMicroplanStatus(); - setMicroplanDetails(); - setMicroplanHypothesis(); - setMicroplanRuleEngine(); - setDraftValues(); - // calling fucntion to cache filtered boundary data - await fetchBoundaryDataWrapper({}); - const filesResponse = await fetchFiles(); - const upload = await setMicroplanUpload(filesResponse); - sessionObj.upload = upload; - return sessionObj; - } catch (error) { - console.error(error.message); - } - }, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js deleted file mode 100644 index 066f47c47f3..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js +++ /dev/null @@ -1,880 +0,0 @@ -import ExcelJS from "exceljs"; -import { - freezeSheetValues, - freezeWorkbookValues, - hideUniqueIdentifierColumn, - performUnfreezeCells, - unfreezeColumnsByHeader, - updateFontNameToRoboto, -} from "../utils/excelUtils"; -import { addBoundaryData, createTemplate, fetchBoundaryData, filterBoundaries } from "../utils/createTemplate"; -import { BOUNDARY_DATA_SHEET, EXCEL, FACILITY_DATA_SHEET, SCHEMA_PROPERTIES_PREFIX, SHEET_COLUMN_WIDTH, commonColumn } from "../configs/constants"; -import shp from "shpjs"; -import JSZip from "jszip"; -import { checkForErrorInUploadedFileExcel } from "../utils/excelValidations"; -import { convertJsonToXlsx } from "../utils/jsonToExcelBlob"; -import { parseXlsxToJsonMultipleSheets } from "../utils/exceltojson"; -import { geojsonValidations } from "../utils/geojsonValidations"; - -// Function for checking the uploaded file for nameing conventions -export const validateNamingConvention = (file, namingConvention, setToast, t) => { - try { - let processedConvention = namingConvention.replace("$", ".[^.]*$"); - const regx = new RegExp(processedConvention); - - if (regx && !regx.test(file.name)) { - setToast({ - state: "error", - message: t("ERROR_NAMING_CONVENSION"), - }); - return false; - } - return true; - } catch (error) { - console.error(error.message); - setToast({ - state: "error", - message: t("ERROR_UNKNOWN"), - }); - } -}; - -// Function for reading ancd checking geojson data -export const readGeojson = async (file, t) => { - return new Promise((resolve, reject) => { - if (!file) return resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); - - const reader = new FileReader(); - reader.onload = (e) => { - try { - const geoJSONData = JSON.parse(e.target.result); - const trimmedGeoJSONData = trimJSON(geoJSONData); - resolve({ valid: true, geojsonData: trimmedGeoJSONData }); - } catch (error) { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_INCORRECT_FORMAT") } }); - } - }; - reader.onerror = (error) => { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") } }); - }; - - reader.readAsText(file); - }); -}; - -// Function to recursively trim leading and trailing spaces from string values in a JSON object -export const trimJSON = (jsonObject) => { - if (typeof jsonObject !== "object") { - return jsonObject; // If not an object, return as is - } - - if (Array.isArray(jsonObject)) { - return jsonObject.map((item) => trimJSON(item)); // If it's an array, recursively trim each item - } - - const trimmedObject = {}; - for (const key in jsonObject) { - if (Object.hasOwn(jsonObject, key)) { - const value = jsonObject[key]; - // Trim string values, recursively trim objects - trimmedObject[key.trim()] = typeof value === "string" ? value.trim() : typeof value === "object" ? trimJSON(value) : value; - } - } - return trimmedObject; -}; -// Function for reading and validating shape file data -export const readAndValidateShapeFiles = async (file, t, namingConvention) => { - return new Promise((resolve, reject) => { - const readAndValidate = async () => { - if (!file) { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); - } - const fileRegex = new RegExp(namingConvention.replace("$", ".*$")); - // File Size Check - const fileSizeInBytes = file.size; - const maxSizeInBytes = 2 * 1024 * 1024 * 1024; // 2 GB - - // Check if file size is within limit - if (fileSizeInBytes > maxSizeInBytes) - resolve({ valid: false, message: t("ERROR_FILE_SIZE"), toast: { state: "error", message: t("ERROR_FILE_SIZE") } }); - - try { - const zip = await JSZip.loadAsync(file); - const isEPSG4326 = await checkProjection(zip); - if (!isEPSG4326) { - resolve({ valid: false, message: t("ERROR_WRONG_PRJ"), toast: { state: "error", message: t("ERROR_WRONG_PRJ") } }); - } - const files = Object.keys(zip.files); - const allFilesMatchRegex = files.every((fl) => { - return fileRegex.test(fl); - }); - let regx = new RegExp(namingConvention.replace("$", "\\.shp$")); - const shpFile = zip.file(regx)[0]; - regx = new RegExp(namingConvention.replace("$", "\\.shx$")); - const shxFile = zip.file(regx)[0]; - regx = new RegExp(namingConvention.replace("$", "\\.dbf$")); - const dbfFile = zip.file(regx)[0]; - - let geojson; - if (shpFile && dbfFile) { - const shpArrayBuffer = await shpFile.async("arraybuffer"); - const dbfArrayBuffer = await dbfFile.async("arraybuffer"); - - geojson = shp.combine([shp.parseShp(shpArrayBuffer), shp.parseDbf(dbfArrayBuffer)]); - } - if (shpFile && dbfFile && shxFile && allFilesMatchRegex) resolve({ valid: true, data: geojson }); - else if (!allFilesMatchRegex) - resolve({ - valid: false, - message: [t("ERROR_CONTENT_NAMING_CONVENSION")], - toast: { state: "error", data: geojson, message: t("ERROR_CONTENT_NAMING_CONVENSION") }, - }); - else if (!shpFile) - resolve({ valid: false, message: [t("ERROR_SHP_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHP_MISSING") } }); - else if (!dbfFile) - resolve({ valid: false, message: [t("ERROR_DBF_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_DBF_MISSING") } }); - else if (!shxFile) - resolve({ valid: false, message: [t("ERROR_SHX_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHX_MISSING") } }); - } catch (error) { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); - } - }; - readAndValidate(); - }); -}; - -// Function for projections check in case of shapefile data -export const checkProjection = async (zip) => { - const prjFile = zip.file(/.prj$/i)[0]; - if (!prjFile) { - return "absent"; - } - - const prjText = await prjFile.async("text"); - - if (prjText.includes("GEOGCS") && prjText.includes("WGS_1984") && prjText.includes("DATUM") && prjText.includes("D_WGS_1984")) { - return "EPSG:4326"; - } - return false; -}; - -// find readMe as per campaign, template identifier and file type -export const findReadMe = (readMeCollection, campaignType, type, section) => { - if (!readMeCollection) return readMeCollection; - return ( - readMeCollection.find( - (readMe) => readMe.fileType === type && readMe.templateIdentifier === section && (!readMe.campaignType || readMe.campaignType === campaignType) - )?.data || {} - ); -}; - -// Function to handle the template download -export const downloadTemplate = async ({ - campaignType, - type, - section, - setToast, - campaignData, - hierarchyType, - Schemas, - HierarchyConfigurations, - setLoader, - hierarchy, - readMeData, - readMeSheetName, - t, -}) => { - try { - setLoader("LOADING"); - await delay(100); - // Find the template based on the provided parameters - const schema = getSchema(campaignType, type, section, Schemas); - const hierarchyLevelName = HierarchyConfigurations?.find((item) => item.name === "devideBoundaryDataBy")?.value; - const filteredReadMeData = findReadMe(readMeData, campaignType, type, section); - let template = await createTemplate({ - hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, - hierarchyLevelName, - addFacilityData: schema?.template?.includeFacilityData, - schema, - boundaries: campaignData?.boundaries, - tenantId: Digit.ULBService.getCurrentTenantId(), - hierarchyType, - readMeData: filteredReadMeData, - readMeSheetName, - t, - }); - const translatedTemplate = translateTemplate(template, t); - - // Create a new workbook - const workbook = new ExcelJS.Workbook(); - - formatTemplate(translatedTemplate, workbook); - - // Color headers - colorHeaders( - workbook, - [...hierarchy.map((item) => t(item)), t(commonColumn)], - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], - [] - ); - - formatAndColorReadMeFile( - workbook, - filteredReadMeData?.map((item) => item?.header), - readMeSheetName - ); - - // protextData - await protectData({ - workbook, - hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, - addFacilityData: schema?.template?.includeFacilityData, - schema, - t, - }); - - // Write the workbook to a buffer - workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { - // Create a Blob from the buffer - const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); - // Create a URL for the Blob - const url = URL.createObjectURL(blob); - // Create a link element and simulate click to trigger download - const link = document.createElement("a"); - link.href = url; - link.download = `${t(section)}.xlsx`; - link.click(); - // Revoke the URL to release the Blob - URL.revokeObjectURL(url); - setLoader(false); - }); - } catch (error) { - setLoader(false); - console.error(error?.message); - setToast({ state: "error", message: t("ERROR_DOWNLOADING_TEMPLATE") }); - } -}; - -export const formatAndColorReadMeFile = (workbook, headerSet, readMeSheetName) => { - const readMeSheet = workbook.getWorksheet(readMeSheetName); - if (!readMeSheet) return; - setAndFormatHeaders(readMeSheet); - formatWorksheet(readMeSheet, headerSet); -}; - -export function setAndFormatHeaders(worksheet) { - const row = worksheet.getRow(1); - // Color the header cell - row.eachCell((cell) => { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "f25449" }, // Header cell color - }; - cell.alignment = { vertical: "middle", horizontal: "center", wrapText: true }; // Center align and wrap text - cell.font = { bold: true }; - }); -} -export function formatWorksheet(worksheet, headerSet) { - // Add the data rows with text wrapping - const lineHeight = 15; // Set an approximate line height - const maxCharactersPerLine = 100; // Set a maximum number of characters per line for wrapping - - worksheet.eachRow((row) => { - row.eachCell({ includeEmpty: true }, (cell) => { - cell.alignment = { vertical: "middle", horizontal: "left", wrapText: true }; // Apply text wrapping - // Calculate the required row height based on content length - const numberOfLines = Math.ceil(cell?.value.length / maxCharactersPerLine); - row.height = numberOfLines * lineHeight; - - // Make the header text bold - if (headerSet?.includes(cell.value)) { - cell.font = { bold: true }; - } - }); - }); - worksheet.getColumn(1).width = 130; -} - -export const protectData = async ({ workbook, hierarchyLevelWiseSheets = true, addFacilityData = false, schema, t }) => { - if (hierarchyLevelWiseSheets) { - if (addFacilityData) { - await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); - await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); - if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { - let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); - await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); - } - if (schema?.template?.facilitySchemaApiMapping) { - } else { - } - } else { - await freezeWorkbookValues(workbook); - await unfreezeColumnsByHeader( - workbook, - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] - ); - } - } else { - // total boundary Data in one sheet - if (addFacilityData) { - await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); - await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); - if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { - let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); - await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); - } - - if (schema?.template?.facilitySchemaApiMapping) { - } else { - } - } else { - await freezeWorkbookValues(workbook); - await unfreezeColumnsByHeader( - workbook, - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] - ); - } - } -}; - -export const colorHeaders = async (workbook, headerList1, headerList2, headerList3) => { - try { - // Iterate through each sheet - workbook.eachSheet((sheet, sheetId) => { - // Get the first row - const firstRow = sheet.getRow(1); - - // Iterate through each cell in the first row - firstRow.eachCell((cell, colNumber) => { - const cellValue = cell.value.toString(); - - // Check conditions and set colors - if (headerList1?.includes(cellValue)) { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "ff9248" }, - }; - } else if (headerList2?.includes(cellValue)) { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "93C47D" }, - }; - } else if (headerList3?.includes(cellValue)) { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "CCCC00" }, - }; - } - }); - }); - } catch (error) { - console.error("Error coloring headers:", error); - } -}; - -export const formatTemplate = (template, workbook) => { - template.forEach(({ sheetName, data }) => { - // Create a new worksheet with properties - const worksheet = workbook.addWorksheet(sheetName); - data?.forEach((row, index) => { - const worksheetRow = worksheet.addRow(row); - - // Apply fill color to each cell in the first row and make cells bold - if (index === 0) { - worksheetRow.eachCell((cell, colNumber) => { - // Set font to bold - cell.font = { bold: true }; - - // Enable text wrapping - cell.alignment = { wrapText: true }; - // Update column width based on the length of the cell's text - const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width - const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding - worksheet.getColumn(colNumber).width = newWidth; - }); - } - }); - updateFontNameToRoboto(worksheet); - }); -}; - -export const translateTemplate = (template, t) => { - // Initialize an array to hold the transformed result - const transformedResult = []; - - // Iterate over each sheet in the divided data - for (const sheet of template) { - const sheetData = sheet.data; - - // Find the index of the boundaryCode column in the header row - const boundaryCodeIndex = sheetData[0].indexOf(commonColumn); - - const sheetName = t(sheet.sheetName); - const transformedSheet = { - sheetName: sheetName.length > 31 ? sheetName.slice(0, 31) : sheetName, - data: [], - }; - - // Iterate over each row in the sheet data - for (const [rowIndex, row] of sheetData.entries()) { - // Transform each entity in the row using the transformFunction - const transformedRow = row.map((entity, index) => { - // Skip transformation for the boundaryCode column - if ((index === boundaryCodeIndex && rowIndex !== 0) || typeof entity === "number") { - return entity; - } - return t(entity); - }); - transformedSheet.data.push(transformedRow); - } - - // Add the transformed sheet to the transformed result - transformedResult.push(transformedSheet); - } - - return transformedResult; -}; - -// get schema for validation -export const getSchema = (campaignType, type, section, schemas) => { - return schemas.find((schema) => { - if (!schema.campaignType) { - return schema.type === type && schema.section === section; - } - return schema.campaignType === campaignType && schema.type === type && schema.section === section; - }); -}; - -// Performs resource mapping and data filtering for Excel files based on provided schema data, hierarchy, and file data. -export const resourceMappingAndDataFilteringForExcelFiles = (schemaData, hierarchy, selectedFileType, fileDataToStore, t) => { - const resourceMappingData = []; - const newFileData = {}; - if (selectedFileType.id === EXCEL && fileDataToStore) { - // Extract all unique column names from fileDataToStore and then doing thir resource mapping - const columnForMapping = new Set(Object.values(fileDataToStore).flatMap((value) => value?.[0] || [])); - if (schemaData?.schema?.["Properties"]) { - const schemaKeys = Object.keys(schemaData.schema["Properties"]) - .map((item) => generateLocalisationKeyForSchemaProperties(item)) - .concat([...hierarchy, commonColumn]); - schemaKeys.forEach((item) => { - if (columnForMapping.has(t(item))) { - resourceMappingData.push({ - mappedFrom: t(item), - mappedTo: revertLocalisationKey(item), - }); - } - }); - } - - // Filtering the columns with respect to the resource mapping and removing the columns that are not needed - Object.entries(fileDataToStore).forEach(([key, value]) => { - const data = []; - const headers = []; - const toRemove = []; - if (value && value.length > 0) { - value[0].forEach((item, index) => { - const mappedTo = resourceMappingData.find((e) => e.mappedFrom === item)?.mappedTo; - if (!mappedTo) { - toRemove.push(index); - return; - } - headers.push(mappedTo); - return; - }); - for (let i = 1; i < value?.length; i++) { - let temp = []; - for (let j = 0; j < value[i].length; j++) { - if (!toRemove.includes(j)) { - temp.push(value[i][j]); - } - } - data.push(temp); - } - } - newFileData[key] = [headers, ...data]; - }); - } - return { tempResourceMappingData: resourceMappingData, tempFileDataToStore: newFileData }; -}; -export const revertLocalisationKey = (localisedCode) => { - if (!localisedCode || !localisedCode.startsWith(SCHEMA_PROPERTIES_PREFIX + "_")) { - return localisedCode; - } - return localisedCode.substring(SCHEMA_PROPERTIES_PREFIX.length + 1); -}; -export const prepareExcelFileBlobWithErrors = async (data, errors, schema, hierarchy, readMeData, readMeSheetName, t) => { - let tempData = [...data]; - // Process each dataset within the data object - const processedData = {}; - const schemaCols = schema?.schema?.Properties ? Object.keys(schema.schema.Properties) : []; - for (const sheet of tempData) { - const dataset = [...sheet.data]; - - // Add the 'error' column to the header - dataset[0] = dataset[0].map((item) => { - if (item !== commonColumn && schemaCols.includes(item)) { - return t(generateLocalisationKeyForSchemaProperties(item)); - } - return t(item); - }); - if (sheet.sheetName !== t(BOUNDARY_DATA_SHEET) && sheet.sheetName !== t(readMeSheetName)) { - // Process each data row - if (errors) { - dataset[0].push(t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN")); - let headerCount = 0; - for (let i = 1; i < dataset.length; i++) { - const row = dataset[i]; - if (i === 1 && row) { - headerCount = row.length; - } - - if (headerCount > row.length) { - row.push(...Array(headerCount - row.length).fill("")); - } - - // Check if there are errors for the given commonColumnData - const errorInfo = errors?.[sheet.sheetName]?.[i - 1]; - if (errorInfo) { - let rowDataAddOn = Object.entries(errorInfo) - .map(([key, value]) => { - return `${t(key)}: ${value.map((item) => t(item)).join(", ")}`; - }) - .join(". "); - row.push(t("MICROPLAN_ERROR_STATUS_INVALID"), rowDataAddOn); - } else { - row.push(""); - } - } - } - } - processedData[sheet.sheetName] = dataset; - } - const errorColumns = ["MICROPLAN_ERROR_STATUS_COLUMN", "MICROPLAN_ERROR_COLUMN"]; - const style = { - font: { color: { argb: "B91900" } }, - border: { - top: { style: "thin", color: { argb: "B91900" } }, - left: { style: "thin", color: { argb: "B91900" } }, - bottom: { style: "thin", color: { argb: "B91900" } }, - right: { style: "thin", color: { argb: "B91900" } }, - }, - }; - const workbook = await convertToWorkBook(processedData, { errorColumns, style }); - colorHeaders( - workbook, - [...hierarchy.map((item) => t(item)), t(commonColumn)], - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], - [t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN")] - ); - - formatAndColorReadMeFile( - workbook, - readMeData?.map((item) => item?.header), - readMeSheetName - ); - - // protextData - await protectData({ - workbook, - hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, - addFacilityData: schema?.template?.includeFacilityData, - schema, - t, - }); - return await workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { - // Create a Blob from the buffer - return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); - }); - // return xlsxBlob; -}; -export const convertToWorkBook = async (jsonData, columnWithStyle) => { - const workbook = new ExcelJS.Workbook(); - - // Iterate over each sheet in jsonData - for (const [sheetName, data] of Object.entries(jsonData)) { - // Create a new worksheet - const worksheet = workbook.addWorksheet(sheetName); - - // Convert data to worksheet - for (const row of data) { - const newRow = worksheet.addRow(row); - const rowHasData = row?.filter((item) => item !== "").length !== 0; - // Apply red font color to the errorColumn if it exists - if (rowHasData && columnWithStyle?.errorColumns) { - for (const errorColumn of columnWithStyle?.errorColumns) { - const errorColumnIndex = data[0].indexOf(errorColumn); - if (errorColumnIndex !== -1) { - const columnIndex = errorColumnIndex + 1; - if (columnIndex > 0) { - const newCell = newRow.getCell(columnIndex); - if (columnWithStyle.style && newCell) for (const key in columnWithStyle.style) newCell[key] = columnWithStyle.style[key]; - } - } - } - } - } - - // Make the first row bold - if (worksheet.getRow(1)) { - worksheet.getRow(1).font = { bold: true }; - } - - // Set column widths - const columnCount = data?.[0]?.length || 0; - const wscols = Array(columnCount).fill({ width: 30 }); - wscols.forEach((col, colIndex) => { - worksheet.getColumn(colIndex + 1).width = col.width; - }); - } - return workbook; -}; -export const boundaryDataGeneration = async (schemaData, campaignData, t) => { - let boundaryDataAgainstBoundaryCode = {}; - if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { - try { - const rootBoundary = campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable - const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; - let boundaryData = sessionData.filteredBoundaries; - let filteredBoundaries; - if (!boundaryData) { - // Only fetch boundary data if not present in session storage - boundaryData = await fetchBoundaryData(Digit.ULBService.getCurrentTenantId(), campaignData?.hierarchyType, rootBoundary?.[0]?.code); - filteredBoundaries = filterBoundaries(boundaryData, campaignData?.boundaries); - - // Update the session storage with the new filtered boundaries - Digit.SessionStorage.set("microplanHelperData", { - ...sessionData, - filteredBoundaries: filteredBoundaries, - }); - } else { - filteredBoundaries = boundaryData; - } - const xlsxData = addBoundaryData([], filteredBoundaries, campaignData?.hierarchyType)?.[0]?.data; - xlsxData.forEach((item, i) => { - if (i === 0) return; - let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn); - if (boundaryCodeIndex >= item.length) { - // If boundaryCodeIndex is out of bounds, return the item as is - boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(t); - } else { - // Otherwise, remove the element at boundaryCodeIndex - boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item - .slice(0, boundaryCodeIndex) - .concat(item.slice(boundaryCodeIndex + 1)) - .map(t); - } - }); - return boundaryDataAgainstBoundaryCode; - } catch (error) { - console.error(error?.message); - } - } -}; - -export const handleExcelFile = async ( - file, - schemaData, - hierarchy, - selectedFileType, - boundaryDataAgainstBoundaryCode, - setUploadedFileError, - t, - campaignData, - readMeSheetName -) => { - try { - // Converting the file to preserve the sequence of columns so that it can be stored - let fileDataToStore = await parseXlsxToJsonMultipleSheets(file, { header: 0 }); - const additionalSheets = []; - if (fileDataToStore[t(BOUNDARY_DATA_SHEET)]) { - additionalSheets.push({ sheetName: t(BOUNDARY_DATA_SHEET), data: fileDataToStore[t(BOUNDARY_DATA_SHEET)], position: -1 }); - delete fileDataToStore[t(BOUNDARY_DATA_SHEET)]; - } - if (fileDataToStore[t(readMeSheetName)]) { - additionalSheets.push({ sheetName: t(readMeSheetName), data: fileDataToStore[t(readMeSheetName)], position: 0 }); - delete fileDataToStore[t(readMeSheetName)]; - } - let { tempResourceMappingData, tempFileDataToStore } = resourceMappingAndDataFilteringForExcelFiles( - schemaData, - hierarchy, - selectedFileType, - fileDataToStore, - t - ); - fileDataToStore = await convertJsonToXlsx(tempFileDataToStore); - // Converting the input file to json format - let result = await parseXlsxToJsonMultipleSheets(fileDataToStore, { header: 1 }); - if (result?.error) { - return { - check: false, - interruptUpload: true, - error: result.error, - fileDataToStore: {}, - toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") }, - }; - } - let extraColumns = [commonColumn]; - // checking if the hierarchy and common column is present the uploaded data - extraColumns = [...hierarchy, commonColumn]; - let data = Object.values(tempFileDataToStore); - let errorMsg; - let errors; // object containing the location and type of error - let toast; - let hierarchyDataPresent = true; - let latLngColumns = - Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isLocationDataColumns) { - acc.push(key); - } - return acc; - }, []) || []; - data.forEach((item) => { - const keys = item[0]; - if (keys?.length !== 0) { - if (!extraColumns?.every((e) => keys.includes(e))) { - if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { - hierarchyDataPresent = false; - } else { - errorMsg = { - check: false, - interruptUpload: true, - error: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT"), - fileDataToStore: {}, - toast: { state: "error", message: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT") }, - }; - } - } - if (!latLngColumns?.every((e) => keys.includes(e))) { - toast = { state: "warning", message: t("ERROR_UPLOAD_EXCEL_LOCATION_DATA_MISSING") }; - } - } - }); - if (errorMsg && !errorMsg?.check) return errorMsg; - // Running Validations for uploaded file - let response = await checkForErrorInUploadedFileExcel(result, schemaData.schema, t); - if (!response.valid) setUploadedFileError(response.message); - errorMsg = response.message; - errors = response.errors; - const missingProperties = response.missingProperties; - let check = response.valid; - try { - if ( - schemaData && - !schemaData.doHierarchyCheckInUploadedData && - !hierarchyDataPresent && - boundaryDataAgainstBoundaryCode && - (!missingProperties || [...missingProperties]?.includes(commonColumn)) - ) { - let tempBoundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; - for (const sheet in tempFileDataToStore) { - const commonColumnIndex = tempFileDataToStore[sheet]?.[0]?.indexOf(commonColumn); - if (commonColumnIndex !== -1) { - const dataCollector = []; - for (let index = 0; index < tempFileDataToStore[sheet].length; index++) { - let row = tempFileDataToStore[sheet][index]; - const commonColumnValues = row[commonColumnIndex]?.split(",").map((item) => item.trim()); - if (!commonColumnValues) { - dataCollector.push([...new Array(hierarchy.length).fill(""), ...row]); - continue; - } - for (const value of commonColumnValues) { - const newRowData = [...row]; - newRowData[commonColumnIndex] = value; - dataCollector.push([ - ...(tempBoundaryDataAgainstBoundaryCode[value] - ? tempBoundaryDataAgainstBoundaryCode[value] - : index !== 0 - ? new Array(hierarchy.length).fill("") - : []), - ...newRowData, - ]); - } - } - tempFileDataToStore[sheet] = dataCollector; - } - - tempFileDataToStore[sheet][0] = [...hierarchy, ...tempFileDataToStore[sheet][0]]; - } - } - } catch (error) { - console.error("Error in boundary adding operaiton: ", error); - } - tempFileDataToStore = addMissingPropertiesToFileData(tempFileDataToStore, missingProperties); - return { check, errors, errorMsg, fileDataToStore: tempFileDataToStore, tempResourceMappingData, toast, additionalSheets }; - } catch (error) { - console.error("Error in handling Excel file:", error.message); - } -}; -export const addMissingPropertiesToFileData = (data, missingProperties) => { - if (!data || !missingProperties) return data; - let tempData = {}; - Object.entries(data).forEach(([key, value], index) => { - const filteredMissingProperties = [...missingProperties]?.reduce((acc, item) => { - if (!value?.[0]?.includes(item)) { - acc.push(item); - } - return acc; - }, []); - const newTempHeaders = value?.[0].length !== 0 ? [...value[0], ...filteredMissingProperties] : [...filteredMissingProperties]; - tempData[key] = [newTempHeaders, ...value.slice(1)]; - }); - return tempData; -}; - -export const handleGeojsonFile = async (file, schemaData, setUploadedFileError, t) => { - // Reading and checking geojson data - const data = await readGeojson(file, t); - if (!data.valid) { - return { check: false, stopUpload: true, toast: data.toast }; - } - - // Running geojson validaiton on uploaded file - let response = geojsonValidations(data.geojsonData, schemaData.schema, t); - if (!response.valid) setUploadedFileError(response.message); - let check = response.valid; - let error = response.message; - let fileDataToStore = data.geojsonData; - return { check, error, fileDataToStore }; -}; - -const generateLocalisationKeyForSchemaProperties = (code) => { - if (!code) return code; - return `${SCHEMA_PROPERTIES_PREFIX}_${code}`; -}; -export const handleShapefiles = async (file, schemaData, setUploadedFileError, selectedFileType, setToast, t) => { - // Reading and validating the uploaded geojson file - let response = await readAndValidateShapeFiles(file, t, selectedFileType["namingConvention"]); - if (!response.valid) { - setUploadedFileError(response.message); - setToast(response.toast); - } - let check = response.valid; - let error = response.message; - let fileDataToStore = response.data; - return { check, error, fileDataToStore }; -}; - -export const convertToSheetArray = (data) => { - if (!data) return []; - const convertedSheetData = []; - for (const [key, value] of Object.entries(data)) { - convertedSheetData.push({ sheetName: key, data: value }); - } - return convertedSheetData; -}; - -//find guideline -export const findGuideLine = (campaignType, type, section, guidelineArray) => { - if (!guidelineArray) return guidelineArray; - return guidelineArray.find( - (guideline) => - guideline.fileType === type && guideline.templateIdentifier === section && (!guideline.campaignType || guideline.campaignType === campaignType) - )?.guidelines; -}; - -// Utility function to introduce a delay -export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js deleted file mode 100644 index a2c50215207..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js +++ /dev/null @@ -1,133 +0,0 @@ -import React, { useState, useEffect } from "react"; -import _ from "lodash"; -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import { configAttendanceApproveModal, configAttendanceRejectModal, configAttendanceCheckModal } from "../config"; - - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const AttendanceActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails, saveAttendanceState}) => { - const [config, setConfig] = useState({}); - - const userUuid = Digit.UserService.getUser()?.info.uuid; - const { isLoading, data:employeeData } = Digit.Hooks.hrms.useHRMSSearch( - { uuids : userUuid }, tenantId - ); - - const empData = employeeData?.Employees[0] - const empDepartment = empData?.assignments?.[0].department - const empDesignation = empData?.assignments?.[0].designation - const empName = empData?.user?.name - - useEffect(() => { - const selectedAction = action?.action - switch(selectedAction) { - case "VERIFY": - submitBasedOnAction(action, 'Verify muster roll') - break; - case "REJECT": - setConfig( - configAttendanceRejectModal({ - t, - action, - empDepartment, - empDesignation, - empName - }) - ) - break; - case "APPROVE": - setConfig( - configAttendanceApproveModal({ - t, - action - }) - ) - break; - case "RESUBMIT": - submitBasedOnAction(action, 'Resubmit muster roll') - break; - case "SAVE": - submitBasedOnAction(action, 'Verify muster roll') - break; - default: - break - } - }, [employeeData]); - - function onSubmit (data) { - submitBasedOnAction(action, data?.comments) - } - - const submitBasedOnAction = (action, comments) => { - let musterRoll = { tenantId, id: applicationDetails?.applicationDetails?.[0]?.applicationData?.id} - let workflow = { action: action?.action, comments: (comments || `${action?.action} done`), assignees: [] } - - const selectedAction = action?.action - switch(selectedAction) { - case "SAVE": - musterRoll.individualEntries = saveAttendanceState?.updatePayload - workflow.action = 'VERIFY' - break; - case "RESUBMIT": - musterRoll.additionalDetails = { computeAttendance : true } - break; - default: - break; - } - const dataTobeSubmitted = {musterRoll, workflow} - submitAction(dataTobeSubmitted) - } - - const cardStyle = () => { - if(config.label.heading === "Processing Details") { - return { - "padding" : "0px" - } - } - return {} - } - - return action && config?.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => {}} - formId="modal-action" - > - - - ) : ( - - ); -} - -export default AttendanceActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js deleted file mode 100644 index 269bbefa1dd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js +++ /dev/null @@ -1,283 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { useQueryClient } from "react-query"; -import { configBPAApproverApplication } from "../config"; -import * as predefinedConfig from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationDetails, applicationData, businessService, moduleCode,workflowDetails }) => { - const mutation1 = Digit.Hooks.obps.useObpsAPI( - applicationData?.landInfo?.address?.city ? applicationData?.landInfo?.address?.city : tenantId, - false - ); - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: workflowDetails?.data?.initialActionState?.nextActions?.filter(ele=>ele?.action==action?.action)?.[0]?.assigneeRoles?.map(role=>({code:role})), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - - const queryClient = useQueryClient(); - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); - const mobileView = Digit.Utils.browser.isMobile() ? true : false; - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { - setError(t(`NOT_SUPPORTED_FILE_TYPE`)) - } else { - try { - const response = await Digit.UploadServices.Filestorage("OBPS", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - const getInspectionDocs = (docs) => { - let refinedDocs = []; - docs && docs.map((doc,ind) => { - refinedDocs.push({ - "documentType":(doc.documentType+"_"+doc.documentType.split("_")[1]).replaceAll("_","."), - "fileStoreId":doc.fileStoreId, - "fileStore":doc.fileStoreId, - "fileName":"", - "dropDownValues": { - "value": (doc.documentType+"_"+doc.documentType.split("_")[1]).replaceAll("_","."), - } - }) - }) - return refinedDocs; - } - - const getQuestion = (data) => { - let refinedQues = []; - var i; - for(i=0; i { - let formdata = [], inspectionOb = []; - - if (data?.additionalDetails?.fieldinspection_pending?.length > 0) { - inspectionOb = data?.additionalDetails?.fieldinspection_pending - } - - if(data.status == "FIELDINSPECTION_INPROGRESS") { - formdata = JSON.parse(sessionStorage.getItem("INSPECTION_DATA")); - formdata?.length > 0 && formdata.map((ob,ind) => { - inspectionOb.push({ - docs: getInspectionDocs(ob.Documents), - date: ob.InspectionDate, - questions: getQuestion(ob), - time: ob?.InspectionTime, - }) - }) - inspectionOb = inspectionOb.filter((ob) => ob.docs && ob.docs.length>0); - } else { - sessionStorage.removeItem("INSPECTION_DATA") - } - - let fieldinspection_pending = [ ...inspectionOb]; - return fieldinspection_pending; - } - - const getDocuments = (applicationData) => { - let documentsformdata = JSON.parse(sessionStorage.getItem("BPA_DOCUMENTS")); - let documentList = []; - documentsformdata.map(doc => { - if(doc?.uploadedDocuments?.[0]?.values?.length > 0) documentList = [...documentList, ...doc?.uploadedDocuments?.[0]?.values]; - if(doc?.newUploadedDocs?.length > 0) documentList = [...documentList, ...doc?.newUploadedDocs] - }); - return documentList; - } - - const getPendingApprovals = () => { - const approvals = Digit.SessionStorage.get("OBPS_APPROVAL_CHECKS"); - const newApprovals = Digit.SessionStorage.get("OBPS_NEW_APPROVALS"); - let result = approvals?.reduce((acc, approval) => approval?.checked ? acc.push(approval?.label) && acc : acc, []); - result = result?.concat(newApprovals !== null?newApprovals.filter(ob => ob.label !== "").map(approval => approval?.label):[]); - return result; - } - - function submit(data) { - let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; - applicationData = { - ...applicationData, - documents: getDocuments(applicationData), - additionalDetails: {...applicationData?.additionalDetails, fieldinspection_pending:getfeildInspection(applicationData), pendingapproval: getPendingApprovals() }, - workflow:{ - action: action?.action, - comment: data?.comments?.length > 0 ? data?.comments : null, - comments: data?.comments?.length > 0 ? data?.comments : null, - assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - assignes: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - varificationDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - }, - action: action?.action, - comment: data?.comments, - assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - wfDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - }; - - const nocDetails = applicationDetails?.nocData?.map(noc => { - const uploadedDocuments = Digit.SessionStorage.get(noc?.nocType) || []; - return { - Noc: { - ...noc, - documents: [ - ...(noc?.documents?noc?.documents:[]), - ...(uploadedDocuments?uploadedDocuments:[]) - ] - } - } - }) - - let nocData = []; - if (nocDetails) { - nocDetails.map(noc => { - if ( - noc?.Noc?.applicationStatus?.toUpperCase() != "APPROVED" && - noc?.Noc?.applicationStatus?.toUpperCase() != "AUTO_APPROVED" && - noc?.Noc?.applicationStatus?.toUpperCase() != "REJECTED" && - noc?.Noc?.applicationStatus?.toUpperCase() != "AUTO_REJECTED" && - noc?.Noc?.applicationStatus?.toUpperCase() != "VOIDED" - ) { - nocData.push(noc); - } - }) - } - - submitAction({ - BPA:applicationData - }, nocData?.length > 0 ? nocData : false, {isStakeholder: false, bpa: true}); - } - - - useEffect(() => { - if (action) { - setConfig( - configBPAApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - assigneeLabel: "WF_ASSIGNEE_NAME_LABEL", - error - }) - ); - } - }, [action, approvers, selectedFinancialYear, uploadedFile, error]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => { }} - formId="modal-action" - isOBPSFlow={true} - popupStyles={mobileView?{width:"720px"}:{}} - style={!mobileView?{minHeight: "45px", height: "auto", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{minHeight: "45px", height: "auto",width:"44%"}} - popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} - > - {PTALoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js deleted file mode 100644 index dc0bfe07776..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js +++ /dev/null @@ -1,153 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { configBPAREGApproverApplication } from "../config"; -import * as predefinedConfig from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - const mobileView = Digit.Utils.browser.isMobile() ? true : false; - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { - setError(t(`NOT_SUPPORTED_FILE_TYPE`)) - } else { - try { - const response = await Digit.UploadServices.Filestorage("OBPS", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - function submit(data) { - let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; - applicationData = { - ...applicationData, - action: action?.action, - comment: data?.comments, - assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - wfDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - }; - submitAction({ - Licenses: [applicationData], - }, false, {isStakeholder: true, bpa: false}); - } - - useEffect(() => { - if (action) { - setConfig( - configBPAREGApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - error - }) - ); - } - }, [action, approvers, uploadedFile, error]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => { }} - formId="modal-action" - isOBPSFlow={true} - popupStyles={mobileView?{width:"720px"}:{}} - style={!mobileView?{height: "45px", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{height:"45px",width:"44%"}} - popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} - > - {PTALoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js deleted file mode 100644 index 95393b5ae05..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js +++ /dev/null @@ -1,190 +0,0 @@ -import { Loader, Modal, FormComposer, WorkflowModal } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect, Fragment } from "react"; -import { configViewBillApproveModal, configViewBillRejectModal, configViewBillCheckModal } from "../config"; -import _ from "lodash"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ExpenditureActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails }) => { - - let { loiNumber, estimateNumber } = Digit.Hooks.useQueryParams(); - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - - const [department, setDepartment] = useState([]); - const [selectedDept,setSelectedDept] = useState({}) - - const [designation, setDesignation] = useState([]); - const [selectedDesignation,setSelectedDesignation] = useState({}) - - const mdmsConfig = { - moduleName: "common-masters", - department : { - masterName: "Department", - localePrefix: "COMMON_MASTERS_DEPARTMENT", - }, - designation : { - masterName: "Designation", - localePrefix: "COMMON_MASTERS_DESIGNATION", - } - } - - const { isLoading: mdmsLoading, data: mdmsData,isSuccess:mdmsSuccess } = Digit.Hooks.useCustomMDMS( - Digit.ULBService.getStateId(), - mdmsConfig?.moduleName, - [{name : mdmsConfig?.designation?.masterName}, {name : mdmsConfig?.department?.masterName}, {name : mdmsConfig?.rejectReasons?.masterName}], - { - select: (data) => { - let designationData = _.get(data, `${mdmsConfig?.moduleName}.${mdmsConfig?.designation?.masterName}`, []); - designationData = designationData.filter((opt) => opt?.active).map((opt) => ({ ...opt, name: `${mdmsConfig?.designation?.localePrefix}_${opt.code}` })); - designationData?.map(designation => {designation.i18nKey = designation?.name}) - - let departmentData = _.get(data, `${mdmsConfig?.moduleName}.${mdmsConfig?.department?.masterName}`, []); - departmentData = departmentData.filter((opt) => opt?.active).map((opt) => ({ ...opt, name: `${mdmsConfig?.department?.localePrefix}_${opt.code}` })); - departmentData?.map(department => { department.i18nKey = department?.name}) - - return {designationData, departmentData}; - }, - enabled: mdmsConfig?.moduleName ? true : false, - } - ); - useEffect(() => { - setDepartment(mdmsData?.departmentData) - setDesignation(mdmsData?.designationData) - }, [mdmsData]); - - - - const { isLoading: approverLoading, isError, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ designations: selectedDesignation?.code, departments: selectedDept?.code, roles: action?.assigneeRoles?.toString(), isActive: true }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: action?.action === "CHECK" || action?.action === "TECHNICALSANCATION"}); - - - employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp?.user?.name || "NA") - - useEffect(() => { - setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees.filter(emp => emp?.nameOfEmp !== "NA") : []) - }, [employeeDatav1]) - - useEffect(() => { - - if(action?.action?.includes("CHECK")){ - setConfig( - configViewBillCheckModal({ - t, - action, - businessService, - approvers, - selectedApprover, - setSelectedApprover, - designation, - selectedDesignation, - setSelectedDesignation, - department, - selectedDept, - setSelectedDept, - approverLoading - }) - ) - }else if(action?.action?.includes("APPROVE")){ - setConfig( - configViewBillApproveModal({ - t, - action - }) - ) - } - else if(action?.action?.includes("REJECT")){ - setConfig( - configViewBillRejectModal({ - t, - action, - }) - ) - } - }, [approvers,designation,department]); - - const dummy_exp_response = { - CHECK : { - header: "Bill Forwarded Successfully", - id: "Bill/2021-22/09/0001", - info: "Bill ID", - message: "Bill has been successfully created and forwarded for approval.", - responseData:{}, - requestData:{}, - links : [] - }, - REJECT : { - header: "Bill Rejected Successfully", - id: "Bill/2021-22/09/0001", - info: "Bill ID", - message: "Bill has been Rejected.", - responseData:{}, - requestData:{}, - links : [] - }, - APPROVE : { - header: "Bill Approved Successfully", - id: "Bill/2021-22/09/0001", - info: "Bill ID", - message: "Bill has been approved", - responseData:{}, - requestData:{}, - links : [] - } - } - - - function submit (_data) { - const workflow = { - action: action?.action, - comment: _data?.comments, - response : dummy_exp_response, - type : "bills", - assignees: selectedApprover?.uuid ? [selectedApprover?.uuid] : undefined - } - submitAction({workflow}); - } - - const cardStyle = () => { - if(config.label.heading === "Processing Details") { - return { - "padding" : "0px" - } - } - return {} - } - - return ( - <> - { - action && config?.form ? - - : - mdmsLoading ? - : null - } - ) -} - -export default ExpenditureActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js deleted file mode 100644 index af0e0e8e701..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js +++ /dev/null @@ -1,298 +0,0 @@ -import { Loader, Modal, FormComposer, Toast } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { useQueryClient } from "react-query"; - -import { configAssignDso, configCompleteApplication, configReassignDSO, configAcceptDso, configRejectApplication } from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData }) => { - const { data: dsoData, isLoading: isDsoLoading, isSuccess: isDsoSuccess, error: dsoError } = Digit.Hooks.fsm.useDsoSearch(tenantId); - const { isLoading, isSuccess, isError, data: applicationData, error } = Digit.Hooks.fsm.useSearch( - tenantId, - { applicationNos: id }, - { - staleTime: Infinity, - select: (details) => { - let { additionalDetails } = details; - - const parseTillObject = (str) => { - if (typeof str === "object") return str; - else return parseTillObject(JSON.parse(str)); - }; - - additionalDetails = parseTillObject(additionalDetails); - return { ...details, additionalDetails }; - }, - } - ); - const client = useQueryClient(); - const stateCode = Digit.ULBService.getStateId(); - const { data: vehicleList, isLoading: isVehicleData, isSuccess: isVehicleDataLoaded } = Digit.Hooks.fsm.useMDMS( - stateCode, - "Vehicle", - "VehicleType", - { staleTime: Infinity } - ); - const [dsoList, setDsoList] = useState([]); - const [vehicleNoList, setVehicleNoList] = useState([]); - const [config, setConfig] = useState({}); - const [dso, setDSO] = useState(null); - const [vehicleNo, setVehicleNo] = useState(null); - const [vehicleMenu, setVehicleMenu] = useState([]); - const [vehicle, setVehicle] = useState(null); - const [defaultValues, setDefautValue] = useState({ - capacity: vehicle?.capacity, - wasteCollected: vehicle?.capacity, - }); - // const [toastError, setToastError] = useState(false); - const { data: Reason, isLoading: isReasonLoading } = Digit.Hooks.fsm.useMDMS(stateCode, "FSM", "Reason", { staleTime: Infinity }, [ - "ReassignReason", - "RejectionReason", - "DeclineReason", - "CancelReason", - ]); - - const [reassignReason, selectReassignReason] = useState(null); - const [rejectionReason, setRejectionReason] = useState(null); - const [declineReason, setDeclineReason] = useState(null); - const [cancelReason, selectCancelReason] = useState(null); - - const [formValve, setFormValve] = useState(false); - - useEffect(() => { - if (isSuccess && isVehicleDataLoaded) { - const [vehicle] = vehicleList.filter((item) => item.code === applicationData.vehicleType); - setVehicleMenu([vehicle]); - setVehicle(vehicle); - setDefautValue({ - capacity: vehicle?.capacity, - wasteCollected: vehicle?.capacity, - }); - } - }, [isVehicleDataLoaded, isSuccess]); - - useEffect(() => { - if (vehicle && isDsoSuccess) { - const dsoList = dsoData.filter((dso) => dso.vehicles.find((dsoVehicle) => dsoVehicle.type === vehicle.code)); - setDsoList(dsoList); - } - }, [vehicle, isDsoSuccess]); - - useEffect(() => { - if (isSuccess && isDsoSuccess && applicationData.dsoId) { - const [dso] = dsoData.filter((dso) => dso.id === applicationData.dsoId); - const vehicleNoList = dso.vehicles.filter((vehicle) => vehicle.type === applicationData.vehicleType); - setVehicleNoList(vehicleNoList); - } - }, [isSuccess, isDsoSuccess]); - - useEffect(() => { - reassignReason || (actionData && actionData[0] && actionData[0].comment?.length > 0) ? setFormValve(true) : setFormValve(false); - }, [reassignReason]); - - useEffect(() => { - setFormValve(rejectionReason ? true : false); - }, [rejectionReason]); - - useEffect(() => { - setFormValve(declineReason ? true : false); - }, [declineReason]); - - useEffect(() => { - setFormValve(cancelReason ? true : false); - }, [cancelReason]); - - function selectDSO(dsoDetails) { - setDSO(dsoDetails); - } - - function selectVehicleNo(vehicleNo) { - setVehicleNo(vehicleNo); - } - - function selectVehicle(value) { - setVehicle(value); - setDefautValue({ - capacity: value?.capacity, - wasteCollected: value?.capacity, - }); - } - - function addCommentToWorkflow(state, workflow, data) { - workflow.comments = data.comments ? state.code + "~" + data.comments : state.code; - } - - function submit(data) { - const workflow = { action: action }; - - if (dso) applicationData.dsoId = dso.id; - if (vehicleNo && action === "ACCEPT") applicationData.vehicleId = vehicleNo.id; - if (vehicleNo && action === "DSO_ACCEPT") applicationData.vehicleId = vehicleNo.id; - if (vehicle && action === "ASSIGN") applicationData.vehicleType = vehicle.code; - if (data.date) applicationData.possibleServiceDate = new Date(`${data.date}`).getTime(); - if (data.desluged) applicationData.completedOn = new Date(data.desluged).getTime(); - if (data.wasteCollected) applicationData.wasteCollected = data.wasteCollected; - if (reassignReason) addCommentToWorkflow(reassignReason, workflow, data); - if (rejectionReason) addCommentToWorkflow(rejectionReason, workflow, data); - if (declineReason) addCommentToWorkflow(declineReason, workflow, data); - if (cancelReason) addCommentToWorkflow(cancelReason, workflow, data); - - submitAction({ fsm: applicationData, workflow }); - } - useEffect(() => { - switch (action) { - case "DSO_ACCEPT": - case "ACCEPT": - setFormValve(vehicleNo ? true : false); - return setConfig( - configAcceptDso({ - t, - dsoData, - dso, - vehicle, - vehicleNo, - vehicleNoList, - selectVehicleNo, - action, - }) - ); - - case "ASSIGN": - case "GENERATE_DEMAND": - case "FSM_GENERATE_DEMAND": - setFormValve(dso && vehicle ? true : false); - return setConfig( - configAssignDso({ - t, - dsoData, - dso, - selectDSO, - vehicleMenu, - vehicle, - selectVehicle, - action, - }) - ); - case "REASSIGN": - case "REASSING": - case "FSM_REASSING": - dso && vehicle && (reassignReason || (actionData && actionData[0] && actionData[0].comment?.length > 0)) - ? setFormValve(true) - : setFormValve(false); - return setConfig( - configReassignDSO({ - t, - dsoData, - dso, - selectDSO, - vehicleMenu, - vehicle, - selectVehicle, - reassignReasonMenu: Reason?.ReassignReason, - reassignReason, - selectReassignReason, - action, - showReassignReason: actionData && actionData[0] && actionData[0].comment?.length > 0 ? false : true, - }) - ); - case "COMPLETE": - case "COMPLETED": - setFormValve(true); - return setConfig(configCompleteApplication({ t, vehicle, applicationCreatedTime: applicationData?.auditDetails?.createdTime, action })); - case "SUBMIT": - case "FSM_SUBMIT": - return history.push(`/${window?.contextPath}/employee/fsm/modify-application/` + applicationNumber); - case "DECLINE": - case "DSO_REJECT": - //declinereason - setFormValve(declineReason ? true : false); - return setConfig( - configRejectApplication({ - t, - rejectMenu: Reason?.DeclineReason, - setReason: setDeclineReason, - reason: declineReason, - action, - }) - ); - case "REJECT": - case "SENDBACK": - // rejectionReason - setFormValve(rejectionReason ? true : false); - return setConfig( - configRejectApplication({ - t, - rejectMenu: Reason?.RejectionReason, - setReason: setRejectionReason, - reason: rejectionReason, - action, - }) - ); - case "CANCEL": - ///cancellreason - setFormValve(cancelReason ? true : false); - return setConfig( - configRejectApplication({ - t, - rejectMenu: Reason?.CancelReason, - setReason: selectCancelReason, - reason: cancelReason, - action, - }) - ); - - case "PAY": - case "ADDITIONAL_PAY_REQUEST": - case "FSM_PAY": - return history.push(`/${window?.contextPath}/employee/payment/collect/FSM.TRIP_CHARGES/${applicationNumber}`); - default: - break; - } - }, [action, isDsoLoading, dso, vehicleMenu, rejectionReason, vehicleNo, vehicleNoList, Reason]); - - return action && config.form && !isDsoLoading && !isReasonLoading && isVehicleDataLoaded ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => {}} - formId="modal-action" - isDisabled={!formValve} - > - - {/* {toastError && } */} - - ) : ( - - ); -}; - -export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js deleted file mode 100644 index 09266ca1b7b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js +++ /dev/null @@ -1,169 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { useQueryClient } from "react-query"; -import { useHistory } from "react-router-dom"; -import { configNOCApproverApplication } from "../config"; -import * as predefinedConfig from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { - - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - - const queryClient = useQueryClient(); - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - const mobileView = Digit.Utils.browser.isMobile() ? true : false; - const history = useHistory(); - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { - setError(t(`NOT_SUPPORTED_FILE_TYPE`)) - } else { - try { - const response = await Digit.UploadServices.Filestorage("NOC", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - - function submit(data) { - let enteredDocs = JSON.parse(sessionStorage.getItem("NewNOCDocs")); - let newDocs = applicationData?.documents?.length > 0 ? [...applicationData?.documents] : []; - enteredDocs.map((d,index) => { - newDocs.push(d); - }) - applicationData = { - ...applicationData, - workflow:{ - action: action?.action, - comment: data?.comments ? data?.comments : null, - assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - documents: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - }, - documents: newDocs, - }; - - - submitAction({ - Noc: applicationData, - }, false, {isNoc: true}); - } - - useEffect(() => { - if (action) { - setConfig( - configNOCApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - assigneeLabel: "WF_ASSIGNEE_NAME_LABEL", - error - }) - ); - } - }, [action, approvers, uploadedFile, error]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => { }} - formId="modal-action" - isOBPSFlow={true} - popupStyles={mobileView?{width:"720px"}:{}} - style={!mobileView?{height: "45px", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{height:"45px",width:"44%"}} - popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} - > - {PTALoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js deleted file mode 100644 index 37b3d996177..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js +++ /dev/null @@ -1,190 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; - -import { configPTApproverApplication, configPTAssessProperty } from "../config"; -import * as predefinedConfig from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - const { isLoading: financialYearsLoading, data: financialYearsData } = Digit.Hooks.pt.useMDMS( - tenantId, - businessService, - "FINANCIAL_YEARLS", - {}, - { - details: { - tenantId: Digit.ULBService.getStateId(), - moduleDetails: [{ moduleName: "egf-master", masterDetails: [{ name: "FinancialYear", filter: "[?(@.module == 'PT')]" }] }], - }, - } - ); - - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState(null); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - const [financialYears, setFinancialYears] = useState([]); - const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); - const [disableActionSubmit, setDisableActionSubmit] = useState(false); - - useEffect(() => { - if (financialYearsData && financialYearsData["egf-master"]) { - setFinancialYears(financialYearsData["egf-master"]?.["FinancialYear"]); - } - }, [financialYearsData]); - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else { - try { - const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - function submit(data) { - if (!action?.showFinancialYearsModal) { - let workflow = { action: action?.action, comment: data?.comments, businessService, moduleName: moduleCode }; - workflow["assignes"] = action?.isTerminateState || !selectedApprover ? [] : [selectedApprover]; - if (uploadedFile) - workflow["documents"] = [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ]; - - submitAction({ - Property: { - ...applicationData, - workflow, - }, - }); - } else { - submitAction({ - customFunctionToExecute: action?.customFunctionToExecute, - Assessment: { - financialYear: selectedFinancialYear?.name, - propertyId: applicationData?.propertyId, - tenantId, - source: applicationData?.source, - channel: applicationData?.channel, - assessmentDate: Date.now(), - }, - }); - } - } - - useEffect(() => { - if (action) { - if (action?.showFinancialYearsModal) { - setConfig( - configPTAssessProperty({ - t, - action, - financialYears, - selectedFinancialYear, - setSelectedFinancialYear, - }) - ); - } else { - setConfig( - configPTApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - }) - ); - } - } - }, [action, approvers, financialYears, selectedFinancialYear, uploadedFile]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => {}} - isDisabled={!action.showFinancialYearsModal ? PTALoading || (action?.docUploadRequired && !uploadedFile) : !selectedFinancialYear} - formId="modal-action" - > - {financialYearsLoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js deleted file mode 100644 index f11658a987a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js +++ /dev/null @@ -1,166 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; - -import { configTLApproverApplication } from "../config"; -import * as predefinedConfig from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - const { isLoading: financialYearsLoading, data: financialYearsData } = Digit.Hooks.pt.useMDMS( - tenantId, - businessService, - "FINANCIAL_YEARLS", - {}, - { - details: { - tenantId: Digit.ULBService.getStateId(), - moduleDetails: [{ moduleName: "egf-master", masterDetails: [{ name: "FinancialYear", filter: "[?(@.module == 'TL')]" }] }], - }, - } - ); - - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - const [financialYears, setFinancialYears] = useState([]); - const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); - - useEffect(() => { - if (financialYearsData && financialYearsData["egf-master"]) { - setFinancialYears(financialYearsData["egf-master"]?.["FinancialYear"]); - } - }, [financialYearsData]); - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else { - try { - const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - function submit(data) { - let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; - applicationData = { - ...applicationData, - action: action?.action, - comment: data?.comments, - assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - // assignee: action?.isTerminateState ? [] : [selectedApprover?.uuid], - wfDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - }; - submitAction({ - Licenses: [applicationData], - }); - } - - useEffect(() => { - if (action) { - setConfig( - configTLApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - }) - ); - } - }, [action, approvers, financialYears, selectedFinancialYear, uploadedFile]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => {}} - // isDisabled={!action.showFinancialYearsModal ? PTALoading || (!action?.isTerminateState && !selectedApprover?.uuid) : !selectedFinancialYear} - formId="modal-action" - > - {financialYearsLoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js deleted file mode 100644 index eb64a09804b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js +++ /dev/null @@ -1,261 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { configWSApproverApplication, configWSDisConnectApplication } from "../config"; -import * as predefinedConfig from "../config"; -import cloneDeep from "lodash/cloneDeep"; - - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const convertDateToEpochNew = (dateString, dayStartOrEnd = "dayend") => { - //example input format : "2018-10-02" - try { - const parts = dateString.match(/(\d{4})-(\d{1,2})-(\d{1,2})/); - const DateObj = new Date(Date.UTC(parts[1], parts[3] - 1, parts[2])); - - DateObj.setMinutes(DateObj.getMinutes() + DateObj.getTimezoneOffset()); - if (dayStartOrEnd === "dayend") { - DateObj.setHours(DateObj.getHours() + 24); - DateObj.setSeconds(DateObj.getSeconds() - 1); - } - return DateObj.getTime(); - } catch (e) { - return dateString; - } -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { - setError(t(`NOT_SUPPORTED_FILE_TYPE`)) - } else { - try { - const response = await Digit.UploadServices.Filestorage("WS", file, Digit.ULBService.getCurrentTenantId()); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - console.error("Modal -> err ", err); - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - function submit(data) { - if(applicationData?.isBillAmend){ - const comments = data?.comments ? data.comments : null - - const additionalDetails = { ...applicationData?.billAmendmentDetails?.additionalDetails, comments } - const amendment = { - ...applicationData?.billAmendmentDetails, - workflow:{ - businessId:applicationData?.billAmendmentDetails?.amendmentId, - action:action?.action, - tenantId:tenantId, - businessService:"BS.AMENDMENT", - moduleName:"BS" - }, - additionalDetails, - comment: data?.comments || "", - wfDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - processInstance: { - action: action?.action, - assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], - comment: data?.comments || "", - documents: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : [] - } - } - //amendment?.additionalDetails?.comments = comments - submitAction({AmendmentUpdate:amendment}) - return - } - let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; - applicationData = { - ...applicationData, - action: action?.action, - comment: data?.comments || "", - assignee: !selectedApprover?.uuid ? [] : [selectedApprover?.uuid], - assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], - wfDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - processInstance: { - ...applicationData?.processInstance, - action: action?.action, - assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], - comment: data?.comments || "", - documents: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : [] - } - }; - - if (data?.date) { - const connectionExecutionDate = cloneDeep(data?.date); - applicationData.connectionExecutionDate = convertDateToEpochNew(connectionExecutionDate) - } - if (applicationData?.processInstance?.businessService == "DisconnectWSConnection" || applicationData?.processInstance?.businessService == "DisconnectSWConnection"){ - applicationData?.serviceType == "WATER" ? - submitAction({ WaterConnection: applicationData, disconnectRequest: true }) : - submitAction({ SewerageConnection: applicationData, disconnectRequest: true }) - } else { - const adhocRebateData = sessionStorage.getItem("Digit.ADHOC_ADD_REBATE_DATA"); - const parsedAdhocRebateData = adhocRebateData ? JSON.parse(adhocRebateData) : ""; - if (parsedAdhocRebateData?.value?.adhocPenalty) applicationData.additionalDetails.adhocPenalty = parseInt(parsedAdhocRebateData?.value?.adhocPenalty) || ""; - if (parsedAdhocRebateData?.value?.adhocPenaltyComment) applicationData.additionalDetails.adhocPenaltyComment = parsedAdhocRebateData?.value?.adhocPenaltyComment || ""; - if (parsedAdhocRebateData?.value?.adhocPenaltyReason) applicationData.additionalDetails.adhocPenaltyReason = parsedAdhocRebateData?.value?.adhocPenaltyReason || ""; - if (parsedAdhocRebateData?.value?.adhocRebate) applicationData.additionalDetails.adhocRebate = parseInt(parsedAdhocRebateData?.value?.adhocRebate) || ""; - if (parsedAdhocRebateData?.value?.adhocRebateComment) applicationData.additionalDetails.adhocRebateComment = parsedAdhocRebateData?.value?.adhocRebateComment || ""; - if (parsedAdhocRebateData?.value?.adhocRebateReason) applicationData.additionalDetails.adhocRebateReason = parsedAdhocRebateData?.value?.adhocRebateReason || ""; - applicationData?.serviceType == "WATER" ? submitAction({ WaterConnection: applicationData }) : submitAction({ SewerageConnection: applicationData }); - } - } - - useEffect(() => { - if (applicationData?.processInstance?.businessService == "DisconnectWSConnection" || applicationData?.processInstance?.businessService == "DisconnectSWConnection") { - if (action) { - setConfig( - configWSDisConnectApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - error - }) - ); - } - } else { - if (action) { - setConfig( - configWSApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - error - }) - ); - } - } - }, [action, approvers, uploadedFile, error]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => { }} - formId="modal-action" - > - {PTALoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js deleted file mode 100644 index dd19cf33a1e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js +++ /dev/null @@ -1,262 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { configApproveModal, configRejectModal, configCheckModal } from "../config"; - -import cloneDeep from "lodash/cloneDeep"; - - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const convertDateToEpochNew = (dateString, dayStartOrEnd = "dayend") => { - //example input format : "2018-10-02" - try { - const parts = dateString.match(/(\d{4})-(\d{1,2})-(\d{1,2})/); - const DateObj = new Date(Date.UTC(parts[1], parts[3] - 1, parts[2])); - - DateObj.setMinutes(DateObj.getMinutes() + DateObj.getTimezoneOffset()); - if (dayStartOrEnd === "dayend") { - DateObj.setHours(DateObj.getHours() + 24); - DateObj.setSeconds(DateObj.getSeconds() - 1); - } - return DateObj.getTime(); - } catch (e) { - return dateString; - } -}; - - -const WorksActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails }) => { - //here according to the action selected render appropriate modal - - // const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - // tenantId, - // { - // roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - // isActive: true, - // }, - // { enabled: !action?.isTerminateState } - // ); - let { loiNumber, estimateNumber } = Digit.Hooks.useQueryParams(); - const [config, setConfig] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - - const [department, setDepartment] = useState([]); - const [selectedDept,setSelectedDept] = useState({}) - - const [rejectionReason, setRejectionReason] = useState([]); - const [selectedReason,setSelectedReason] = useState([]) - - const [designation, setDesignation] = useState([]); - const [selectedDesignation,setSelectedDesignation] = useState({}) - - //get approverDept,designation,approver(hrms),rejectionReason - - const rejectReasons = [ - { - name: "Estimate Details are incorrect" - }, - { - name: "Financial Details are incorrect" - }, - { - name: "Agreement Details are incorrect" - }, - { - name: "Vendor Details are incorrect" - }, - { - name: "Attachments provided are wrong" - }, - { - name: "Others" - }, - ] - - const { isLoading: mdmsLoading, data: mdmsData,isSuccess:mdmsSuccess } = Digit.Hooks.useCustomMDMS( - Digit.ULBService.getCurrentTenantId(), - "common-masters", - [ - { - "name": "Designation" - }, - { - "name": "Department" - } - ] - ); - - mdmsData?.["common-masters"]?.Designation?.map(designation => { - designation.i18nKey = `ES_COMMON_DESIGNATION_${designation?.name}` - }) - - mdmsData?.["common-masters"]?.Department?.map(department => { - department.i18nKey = `ES_COMMON_${department?.code}` - }) - // const { data: approverData, isLoading: approverLoading } = Digit.Hooks.useEmployeeSearch( - // tenantId, - // { - // roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - // isActive: true, - // }, - // { enabled: !action?.isTerminateState } - // ); - - - // const { isLoading: approverLoading, isError,isSuccess:approverSuccess, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ Designation: selectedDesignation?.code, Department: selectedDept?.code }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: !!(selectedDept?.code && selectedDesignation?.code) }); - // employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp.user.name) - - - // useEffect(() => { - - // setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - // }, [approverData]); - - useEffect(() => { - - //setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - //setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees : []) - setDepartment(mdmsData?.["common-masters"]?.Department) - setDesignation(mdmsData?.["common-masters"]?.Designation) - setRejectionReason(rejectReasons) - }, [mdmsData]); - - - - const { isLoading: approverLoading, isError, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ designations: selectedDesignation?.code, departments: selectedDept?.code, roles: action?.assigneeRoles?.toString(), isActive: true }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: action?.action === "CHECK" || action?.action === "TECHNICALSANCATION"}); - - - employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp?.user?.name || "NA") - - useEffect(() => { - setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees.filter(emp => emp?.nameOfEmp !== "NA") : []) - }, [employeeDatav1]) - - - // if (employeeDatav1?.Employees?.length > 0) { - // setApprovers(employeeDatav1?.Employees) - // } - - useEffect(() => { - - if(action?.action?.includes("CHECK") || action?.action?.includes("TECHNICALSANCATION")){ - setConfig( - configCheckModal({ - t, - action, - businessService, - approvers, - selectedApprover, - setSelectedApprover, - designation, - selectedDesignation, - setSelectedDesignation, - department, - selectedDept, - setSelectedDept, - approverLoading - }) - ) - }else if(action?.action?.includes("APPROVE") || action?.action?.includes("ADMINSANCTION")){ - setConfig( - configApproveModal({ - t, - action - }) - ) - } - else if(action?.action?.includes("REJECT")){ - setConfig( - configRejectModal({ - t, - action, - rejectReasons, - selectedReason, - setSelectedReason, - loiNumber, - department, - estimateNumber - }) - ) - } - }, [approvers,designation,department]); - - - function submit (_data) { - //make the update object here and call submitAction - //if the action is reject then you need to make a search call and get creater's uuid - const workflow = { - action: action?.action, - comment: _data?.comments, - assignees: selectedApprover?.uuid ? [selectedApprover?.uuid] : undefined - } - - if(action?.action.includes("REJECT")) { - workflow.assignee = [applicationData?.auditDetails?.createdBy] - } - - Object.keys(workflow).forEach(key => { - if (workflow[key] === undefined) { - delete workflow[key]; - } - }); - {estimateNumber ? submitAction({estimate:applicationData,workflow}) : - submitAction({letterOfIndent:applicationData,workflow})} - - } - - // if(mdmsLoading || approverLoading ) { - // return - // } - - - - - - return action && config?.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => { }} - formId="modal-action" - > - {mdmsLoading ? ( - - ) : ( - - )} - - ) : ( - - ); -} - -export default WorksActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js deleted file mode 100644 index 56465790b8b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js +++ /dev/null @@ -1,49 +0,0 @@ -import React, { useState, useEffect } from "react"; -import FSMActionModal from "./FSMActionModal"; -import PTActionModal from "./PTActionModal"; -import TLActionModal from "./TLActionModal"; -import BPAREGActionModal from "./BPAREGActionModal"; -import BPAActionModal from "./BPAActionModal"; -import NOCActionModal from "./NOCActionModal"; -import WNSActionModal from "./WNSActionModal"; -import WorksActionModal from "./WorksActionModal"; -import AttendanceActionModal from "./AttendanceActionModal"; -import ExpenditureActionModal from "./ExpenditureActionModal"; - -const ActionModal = (props) => { - if (props?.businessService.includes("PT")) { - return ; - } - - if (props?.businessService.includes("NewTL") || props?.businessService.includes("TL") || props?.businessService.includes("EDITRENEWAL") || props?.businessService.includes("DIRECTRENEWAL")) { - return ; - } - - if (props?.moduleCode.includes("BPAREG")) { - return ; - } - - if (props?.moduleCode.includes("BPA")) { - return ; - } - - if (props?.moduleCode.includes("NOC")) { - return ; - } - - if (props?.moduleCode.includes("WS")) { - return ; - } - if (props?.moduleCode.includes("works")) { - return ; - } - if (props?.moduleCode.includes("AttendenceMgmt")) { - return ; - } - if (props?.moduleCode.includes("Expenditure")) { - return ; - } - -}; - -export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js deleted file mode 100644 index 7ad3a0f95ce..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js +++ /dev/null @@ -1,80 +0,0 @@ -import React, {useEffect, useRef} from "react"; -import { useTranslation } from "react-i18next"; -import { SubmitBar, ActionBar, Menu } from "@egovernments/digit-ui-react-components"; - -function ApplicationDetailsActionBar({ workflowDetails, displayMenu, onActionSelect, setDisplayMenu, businessService, forcedActionPrefix,ActionBarStyle={},MenuStyle={}, saveAttendanceState }) { - const { t } = useTranslation(); - let user = Digit.UserService.getUser(); - const menuRef = useRef(); - if (window.location.href.includes("/obps") || window.location.href.includes("/noc")) { - const userInfos = sessionStorage.getItem("Digit.citizen.userRequestObject"); - const userInfo = userInfos ? JSON.parse(userInfos) : {}; - user = userInfo?.value; - } - const userRoles = user?.info?.roles?.map((e) => e.code); - let isSingleButton = false; - let isMenuBotton = false; - let actions = workflowDetails?.data?.actionState?.nextActions?.filter((e) => { - return userRoles.some((role) => e.roles?.includes(role)) || !e.roles; - }) || workflowDetails?.data?.nextActions?.filter((e) => { - return userRoles.some((role) => e.roles?.includes(role)) || !e.roles; - }); - - const closeMenu = () => { - setDisplayMenu(false); - } - Digit.Hooks.useClickOutside(menuRef, closeMenu, displayMenu ); - - if (((window.location.href.includes("/obps") || window.location.href.includes("/noc")) && actions?.length == 1) || (actions?.[0]?.redirectionUrl?.pathname.includes("/pt/property-details/")) && actions?.length == 1) { - isMenuBotton = false; - isSingleButton = true; - } else if (actions?.length > 0) { - isMenuBotton = true; - isSingleButton = false; - } - - if(saveAttendanceState?.displaySave) { - isMenuBotton = false; - isSingleButton = true; - actions = [ - { - action: "SAVE", - state: "UPDATED" - } - ] - } - - return ( - - {!workflowDetails?.isLoading && isMenuBotton && !isSingleButton && ( - - {displayMenu && (workflowDetails?.data?.actionState?.nextActions || workflowDetails?.data?.nextActions) ? ( - - ) : null} - setDisplayMenu(!displayMenu)} /> - - )} - {!workflowDetails?.isLoading && !isMenuBotton && isSingleButton && ( - - - - )} - - ); -} - -export default ApplicationDetailsActionBar; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js deleted file mode 100644 index 5596d7b694b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js +++ /dev/null @@ -1,484 +0,0 @@ -import { - BreakLine, - Card, - CardSectionHeader, - CardSubHeader, - CheckPoint, - CollapseAndExpandGroups, - ConnectingCheckPoints, - ViewImages, - Loader, - Row, - StatusTable, - Table, -} from "@egovernments/digit-ui-react-components"; -import { values } from "lodash"; -import React, { Fragment, useCallback, useReducer, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; -import BPADocuments from "./BPADocuments"; -import InspectionReport from "./InspectionReport"; -import NOCDocuments from "./NOCDocuments"; -import PermissionCheck from "./PermissionCheck"; -import PropertyDocuments from "./PropertyDocuments"; -import PropertyEstimates from "./PropertyEstimates"; -import PropertyFloors from "./PropertyFloors"; -import PropertyOwners from "./PropertyOwners"; -import ScruntinyDetails from "./ScruntinyDetails"; -import SubOccupancyTable from "./SubOccupancyTable"; -import TLCaption from "./TLCaption"; -import TLTradeAccessories from "./TLTradeAccessories"; -import TLTradeUnits from "./TLTradeUnits"; -//import WSAdditonalDetails from "./WSAdditonalDetails"; -import WSFeeEstimation from "./WSFeeEstimation"; -//import WSInfoLabel from "../../../ws/src/pageComponents/WSInfoLabel"; -import DocumentsPreview from "./DocumentsPreview"; -import InfoDetails from "./InfoDetails"; -import ViewBreakup from "./ViewBreakup"; -import SubWorkTableDetails from "./SubWorkTableDetails"; - - - -function ApplicationDetailsContent({ - applicationDetails, - workflowDetails, - isDataLoading, - applicationData, - businessService, - timelineStatusPrefix, - showTimeLine = true, - statusAttribute = "status", - paymentsList, - oldValue, - isInfoLabel = false, - noBoxShadow = false, - sectionHeadStyle = false, - modify, - setSaveAttendanceState -}) { - const { t } = useTranslation(); - const [localSearchParams, setLocalSearchParams] = useState(() => ({})); - - - const handleDateRangeChange = useCallback((data) => { - setLocalSearchParams(() => ({ ...data })); - }, []); - - function OpenImage(imageSource, index, thumbnailsToShow) { - window.open(thumbnailsToShow?.fullImage?.[0], "_blank"); - } - - const convertEpochToDateDMY = (dateEpoch) => { - if (dateEpoch == null || dateEpoch == undefined || dateEpoch == "") { - return "NA"; - } - const dateFromApi = new Date(dateEpoch); - let month = dateFromApi.getMonth() + 1; - let day = dateFromApi.getDate(); - let year = dateFromApi.getFullYear(); - month = (month > 9 ? "" : "0") + month; - day = (day > 9 ? "" : "0") + day; - return `${day}/${month}/${year}`; - }; - const getTimelineCaptions = (checkpoint) => { - if (checkpoint.state === "OPEN" || (checkpoint.status === "INITIATED" && !window.location.href.includes("/obps/"))) { - const caption = { - date: convertEpochToDateDMY(applicationData?.auditDetails?.createdTime), - source: applicationData?.channel || "", - }; - return ; - } else if (window.location.href.includes("/obps/") || window.location.href.includes("/noc/") || window.location.href.includes("/ws/")) { - //From BE side assigneeMobileNumber is masked/unmasked with connectionHoldersMobileNumber and not assigneeMobileNumber - const privacy = { uuid: checkpoint?.assignes?.[0]?.uuid, fieldName: ["connectionHoldersMobileNumber"], model: "WaterConnectionOwner" }; - const caption = { - date: checkpoint?.auditDetails?.lastModified, - name: checkpoint?.assignes?.[0]?.name, - mobileNumber: - applicationData?.processInstance?.assignes?.[0]?.uuid === checkpoint?.assignes?.[0]?.uuid && - applicationData?.processInstance?.assignes?.[0]?.mobileNumber - ? applicationData?.processInstance?.assignes?.[0]?.mobileNumber - : checkpoint?.assignes?.[0]?.mobileNumber, - comment: t(checkpoint?.comment), - wfComment: checkpoint.wfComment, - thumbnailsToShow: checkpoint?.thumbnailsToShow, - }; - return ; - } else { - const caption = { - date: `${Digit.DateUtils?.ConvertTimestampToDate(checkpoint.auditDetails.lastModifiedEpoch)} ${Digit.DateUtils?.ConvertEpochToTimeInHours( - checkpoint.auditDetails.lastModifiedEpoch - )} ${Digit.DateUtils?.getDayfromTimeStamp(checkpoint.auditDetails.lastModifiedEpoch)}`, - // name: checkpoint?.assigner?.name, - name: checkpoint?.assignes?.[0]?.name, - // mobileNumber: checkpoint?.assigner?.mobileNumber, - wfComment: checkpoint?.wfComment, - mobileNumber: checkpoint?.assignes?.[0]?.mobileNumber, - }; - - return ; - } - }; - - const getTranslatedValues = (dataValue, isNotTranslated) => { - if (dataValue) { - return !isNotTranslated ? t(dataValue) : dataValue; - } else { - return t("NA"); - } - }; - - const checkLocation = - window.location.href.includes("employee/tl") || window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc"); - const isNocLocation = window.location.href.includes("employee/noc"); - const isBPALocation = window.location.href.includes("employee/obps"); - let isWS = window.location.href.includes("employee/ws") || window.location.href.includes("employee/works")|| window.location.href.includes("employee/project") || window.location.href.includes("employee/estimate") ; - - - - const getRowStyles = (tab="") => { - - if (window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc")) { - return { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; - } else if (checkLocation) { - return { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; - } - else if ( tab==="fieldSurvey") { - return { - justifyContent: "space-between", flexDirection:"column" - } - } - else { - return {}; - } - - }; - const getTextStyles = (tab="") => { - if ( tab==="fieldSurvey" ) { - return { - marginTop:"1rem", - marginBottom:"1rem" - } - } - else { - return {}; - } - - }; - const getLabelStyles = (tab = "") => { - if ( tab === "fieldSurvey") { - return { - width:"100%" - } - } - else { - return {}; - } - - }; - - const getTableStyles = () => { - if (window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc")) { - return { position: "relative", marginTop: "19px" }; - } else if (checkLocation) { - return { position: "relative", marginTop: "19px" }; - } else { - return {}; - } - }; - - const getMainDivStyles = () => { - if ( - window.location.href.includes("employee/obps") || - window.location.href.includes("employee/noc") || - window.location.href.includes("employee/ws") || - window.location.href.includes("employee/works") || - window.location.href.includes("employee/contracts") - ) { - return { lineHeight: "19px", maxWidth: "950px", minWidth: "280px" }; - } else if (checkLocation) { - return { lineHeight: "19px", maxWidth: "600px", minWidth: "280px" }; - } else { - return {}; - } - }; - - const getTextValue = (value) => { - if (value?.skip) return value.value; - else if (value?.isUnit) return value?.value ? `${getTranslatedValues(value?.value, value?.isNotTranslated)} ${t(value?.isUnit)}` : t("N/A"); - else if (value?.value === "Approved") return { `${getTranslatedValues(value?.value, value?.isNotTranslated)}`} - else if (value?.value === "Rejected") return {t(value?.value)} - else return value?.value ? getTranslatedValues(value?.value, value?.isNotTranslated) : t("N/A"); - }; - - const getClickInfoDetails = () => { - if (window.location.href.includes("disconnection") || window.location.href.includes("application")) { - return "WS_DISCONNECTION_CLICK_ON_INFO_LABEL"; - } else { - return "WS_CLICK_ON_INFO_LABEL"; - } - }; - - const getClickInfoDetails1 = () => { - if (window.location.href.includes("disconnection") || window.location.href.includes("application")) { - return "WS_DISCONNECTION_CLICK_ON_INFO1_LABEL"; - } else { - return ""; - } - }; - - const getCardStyles = () => { - let styles = { position: "relative" } - if (noBoxShadow) styles = { ...styles, boxShadow: "none" }; - return styles; - }; - - return ( - - - {isInfoLabel ? ( - - ) : null} - {applicationDetails?.applicationDetails?.map((detail, index) => ( - - -
- {index === 0 && !detail.asSectionHeader ? ( - {t(detail.title)} - ) : ( - - - {isNocLocation ? `${t(detail.title)}` : t(detail.title)} - {detail?.Component ? : null} - - - )} - {/* TODO, Later will move to classes */} - {/* Here Render the table for adjustment amount details detail.isTable is true for that table*/} - {/* {detail?.isTable && ( - - - {detail?.headers.map((header) => ( - - ))} - - - {detail?.tableRows.map((row,index)=>{ - if(index===detail?.tableRows.length - 1){ - return <> -
- - {row.map(element => )} - - - } - return - {row.map(element => )} - })} -
{t(header)}
{t(element)}
{t(element)}
- )} */} - {detail?.isTable && } - - - {detail?.title && - !detail?.title.includes("NOC") && - detail?.values?.map((value, index) => { - if (value.map === true && value.value !== "N/A") { - return } />; - } - if (value?.isLink == true) { - return ( - - - - {t(value?.title)} - - -
- ) : isNocLocation || isBPALocation ? ( - `${t(value.title)}` - ) : ( - t(value.title) - ) - } - text={ -
- - - {value?.value} - - -
- } - last={index === detail?.values?.length - 1} - caption={value.caption} - className="border-none" - rowContainerStyle={getRowStyles()} - /> - ); - } - return ( - { }} />: getTextValue(value)} - last={index === detail?.values?.length - 1} - caption={value.caption} - className="border-none" - /* privacy object set to the Row Component */ - privacy={value?.privacy} - // TODO, Later will move to classes - rowContainerStyle={getRowStyles(detail?.tab)} - textStyle={getTextStyles(detail?.tab)} - labelStyle={getLabelStyles(detail?.tab)} - /> - ); - })} - -
- - - {detail?.additionalDetails?.table - ? detail?.additionalDetails?.table?.weekTable?.tableHeader && ( - <> - - {t(detail?.additionalDetails?.table?.weekTable?.tableHeader)} - - - ) - : null} - - {detail?.additionalDetails?.inspectionReport && ( - - )} - {applicationDetails?.applicationData?.additionalDetails?.fieldinspection_pending?.length > 0 && detail?.additionalDetails?.fiReport && ( - - )} - {/* {detail?.additionalDetails?.FIdocuments && detail?.additionalDetails?.values?.map((doc,index) => ( -
- {doc.isNotDuplicate &&
- - - -
-
-
} -
- )) } */} - {detail?.additionalDetails?.floors && } - {detail?.additionalDetails?.owners && } - {detail?.additionalDetails?.units && } - {detail?.additionalDetails?.accessories && } - {detail?.additionalDetails?.permissions && workflowDetails?.data?.nextActions?.length > 0 && ( - - )} - {detail?.additionalDetails?.obpsDocuments && ( - - )} - {detail?.additionalDetails?.noc && ( - - )} - {detail?.additionalDetails?.scruntinyDetails && } - {detail?.additionalDetails?.buildingExtractionDetails && } - {detail?.additionalDetails?.subOccupancyTableDetails && ( - - )} - {detail?.additionalDetails?.documentsWithUrl && } - {detail?.additionalDetails?.documents && } - {detail?.additionalDetails?.taxHeadEstimatesCalculation && ( - - )} - {/* {detail?.isWaterConnectionDetails && } */} - {detail?.additionalDetails?.redirectUrl && ( -
- - - {detail?.additionalDetails?.redirectUrl?.title} - - -
- )} - {detail?.additionalDetails?.estimationDetails && } - {detail?.additionalDetails?.estimationDetails && } - - - ))} - {showTimeLine && workflowDetails?.data?.timeline?.length > 0 && ( - - {workflowDetails?.breakLineRequired === undefined ? : workflowDetails?.breakLineRequired ? : null} - {(workflowDetails?.isLoading || isDataLoading) && } - {!workflowDetails?.isLoading && !isDataLoading && ( - - - {/* {t("ES_APPLICATION_DETAILS_APPLICATION_TIMELINE")} */} - {t("WORKS_WORKFLOW_HISTORY")} - - {workflowDetails?.data?.timeline && workflowDetails?.data?.timeline?.length === 1 ? ( - - ) : ( - - {workflowDetails?.data?.timeline && - workflowDetails?.data?.timeline.map((checkpoint, index, arr) => { - return ( - - - - ); - })} - - )} - - )} - - )} - - - ); -} - -export default ApplicationDetailsContent; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js deleted file mode 100644 index 9540495f32a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js +++ /dev/null @@ -1,74 +0,0 @@ -import React from "react"; -import { Toast } from "@egovernments/digit-ui-react-components"; - -function ApplicationDetailsToast({ t, showToast, closeToast, businessService }) { - if (businessService?.includes("NewTL") || businessService?.includes("TL") || businessService?.includes("EDITRENEWAL")) { - let label = ""; - switch (showToast?.action?.action) { - case "SENDBACK": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_SENDBACK_CHECKLIST_MESSAGE_HEAD"); - break; - case "FORWARD": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_FORWARD_SUCCESS_MESSAGE_MAIN"); - break; - case "APPROVE": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPROVAL_CHECKLIST_MESSAGE_HEAD"); - break; - case "SENDBACKTOCITIZEN": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_SENDBACK_TOCITIZEN_CHECKLIST_MESSAGE_HEAD"); - break; - case "REJECT": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPROVAL_REJ_MESSAGE_HEAD"); - break; - case "RESUBMIT": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPLICATION_RESUBMIT_SUCCESS_MESSAGE_MAIN"); - break; - case "CANCEL": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_TL_CANCELLED_MESSAGE_HEAD"); - break; - default: - label = showToast?.key === "error" ? showToast?.error?.message : t(`ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`); - } - return {showToast && }; - } else if (businessService?.includes("BPA") || businessService?.includes("BPA_LOW") || businessService?.includes("BPA_OC")) { - const getMessage = (messages = []) => { - let returnValue = messages[0]; - if(messages?.length == 2) returnValue = businessService?.includes("BPA_OC") ? t(messages[1]) : t(messages [0]); - else returnValue = t(messages[0]); - return returnValue; - } - let label = ""; - switch (showToast?.action?.action) { - case "REVOCATE": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_REVOCATED_MESSAGE_HEAD", "BPA_APPROVAL_OC_REVOCATED_MESSAGE_HEAD"]); - break; - case "VERIFY_AND_FORWARD": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_FORWARD_SUCCESS_MESSAGE_MAIN"]); - break; - case "SEND_BACK_TO_CITIZEN": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_SENDBACK_SUCCESS_MESSAGE_MAIN"]); - break; - case "APPROVE": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_CHECKLIST_MESSAGE_HEAD"]); - break; - case "REJECT": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_REJECTED_MESSAGE_HEAD", "BPA_OC_APPROVAL_REJECTED_MESSAGE_HEAD"]); - break; - case "FORWARD": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_FORWARD_SUCCESS_MESSAGE_MAIN"]); - break; - case "SEND_BACK_FOR_DOCUMENT_VERIFICATION": - case "SEND_BACK_FOR_FIELD_INSPECTION": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_SENDBACK_SUCCESS_MESSAGE_MAIN"]); - break; - default: - label = showToast?.key === "error" ? showToast?.error?.message : t(`ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`); - } - return {showToast && }; - } else { - const label = showToast?.key === "error" ? showToast?.error?.message : `ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`; - return {showToast && }; - } -} - -export default ApplicationDetailsToast; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js deleted file mode 100644 index e95b9e038cd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js +++ /dev/null @@ -1,54 +0,0 @@ -import { Card, ButtonSelector, CardText, CardSubHeader, Modal, CardSectionHeader, Row } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useTranslation } from "react-i18next"; - -const Close = () => ( - - - - - ); - -const CloseBtn = (props) => { - return ( -
- -
- ); - }; - -function ApplicationDetailsWarningPopup({ action,workflowDetails,businessService,isWarningPop,closeWarningPopup }) { -const { t } = useTranslation(); -const isMobile = window.Digit.Utils.browser.isMobile(); -return ( - - {t("PT_DUES_ARE_PENDING")}} - headerBarEnd={ - { - closeWarningPopup(); - }} - /> - } - hideSubmit={true} - isDisabled={false} - popupStyles={isMobile ? {} : { width: "29%", marginTop: "auto" }} - > - -
-

{t("PT_YOU_HAVE")} ₹{action?.AmountDueForPay} {t("PT_DUE_WARNING_MSG2")}

-
- -
- - window.location.assign(`${window.location.origin}${action?.redirectionUrl?.pathname}`)} style={{ marginLeft: "10px" }} /> -
-
-
- ) -
-) -} - -export default ApplicationDetailsWarningPopup; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js deleted file mode 100644 index 9a1febe081b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js +++ /dev/null @@ -1,234 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { - CardLabel, - Dropdown, - LabelFieldPair, - MultiUploadWrapper, - CardSubHeader -} from "@egovernments/digit-ui-react-components"; -import DocumentsPreview from "./DocumentsPreview"; - -const BPADocuments = ({ t, formData, applicationData, docs, bpaActionsDetails }) => { - const applicationStatus = applicationData?.status || ""; - const actions = bpaActionsDetails?.data?.nextActions || []; - const stateId = Digit.ULBService.getStateId(); - const [documents, setDocuments] = useState(formData?.documents?.documents || []); - const [error, setError] = useState(null); - const [bpaTaxDocuments, setBpaTaxDocuments] = useState([]); - const [enableSubmit, setEnableSubmit] = useState(true) - const [checkRequiredFields, setCheckRequiredFields] = useState(false); - const [checkEnablingDocs, setCheckEnablingDocs] = useState(false); - - const { isLoading: bpaDocsLoading, data: bpaDocs } = Digit.Hooks.obps.useMDMS(stateId, "BPA", ["DocTypeMapping"]); - const { isLoading: commonDocsLoading, data: commonDocs } = Digit.Hooks.obps.useMDMS(stateId, "common-masters", ["DocumentType"]); - - useEffect(() => { - let filtredBpaDocs = []; - if (bpaDocs?.BPA?.DocTypeMapping) { - // filtredBpaDocs = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == "INPROGRESS")) - filtredBpaDocs = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == applicationData?.status ? applicationData?.status : "INPROGRESS" && data.RiskType == applicationData?.riskType && data.ServiceType == applicationData?.additionalDetails?.serviceType && data.applicationType == applicationData?.additionalDetails?.applicationType)) - } - let documentsList = []; - filtredBpaDocs?.[0]?.docTypes?.forEach(doc => { - let code = doc.code; doc.dropdownData = []; doc.uploadedDocuments = []; - commonDocs?.["common-masters"]?.DocumentType?.forEach(value => { - let values = value.code.slice(0, code.length); - if (code === values) { - doc.hasDropdown = true; - value.i18nKey = value.code; - doc.dropdownData.push(value); - } - }); - doc.uploadedDocuments[0] = {}; - doc.uploadedDocuments[0].values = []; - docs?.[0]?.values?.map(upDocs => { - if (code === `${upDocs?.documentType?.split('.')[0]}.${upDocs?.documentType?.split('.')[1]}`) { - doc.uploadedDocuments[0].values.push(upDocs) - } - }) - documentsList.push(doc); - }); - sessionStorage.setItem("BPA_DOCUMENTS", JSON.stringify(documentsList)); - setBpaTaxDocuments(documentsList); - - }, [!bpaDocsLoading, !commonDocsLoading]); - - useEffect(() => { - let count = 0; - bpaTaxDocuments.map(doc => { - let isRequired = false; - documents.map(data => { - if (doc.required && doc.code == `${data.documentType.split('.')[0]}.${data.documentType.split('.')[1]}`) { - isRequired = true; - } - }); - if (!isRequired && doc.required) { - count = count + 1; - } - }); - if ((count == "0" || count == 0) && documents.length > 0) setEnableSubmit(false); - else setEnableSubmit(true); - }, [documents, checkRequiredFields]) - - useEffect(() => { - if ( applicationStatus === "DOC_VERIFICATION_INPROGRESS" && actions?.length > 0 ) setCheckEnablingDocs(true); - else setCheckEnablingDocs(false); - }, [applicationData, bpaActionsDetails]) - - return ( -
- {bpaTaxDocuments?.map((document, index) => { - return ( -
- -
- ); - })} -
- ); -} - -function SelectDocument({ - t, - document: doc, - setDocuments, - error, - setError, - documents, - setCheckRequiredFields, - index, - applicationStatus, - actions, - bpaTaxDocuments, - checkEnablingDocs -}) { - - const filteredDocument = documents?.filter((item) => item?.documentType?.includes(doc?.code))[0]; - const tenantId = Digit.ULBService.getStateId(); - const [selectedDocument, setSelectedDocument] = useState( - filteredDocument - ? { ...filteredDocument, active: true, code: filteredDocument?.documentType, i18nKey: filteredDocument?.documentType } - : doc?.dropdownData?.length === 1 - ? doc?.dropdownData[0] - : {} - ); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(() => filteredDocument?.fileStoreId || null); - const [selectArrayFiles, SetSelectArrayFiles] = useState([]); - const handleSelectDocument = (value) => setSelectedDocument(value); - const allowedFileTypes = /(.*?)(jpg|jpeg|png|image|pdf)$/i; - - function selectfiles(e) { - e && setFile(e.file); - } - - - useEffect(() => { - if (selectedDocument?.code) { - setDocuments((prev) => { - const filteredDocumentsByDocumentType = prev?.filter((item) => item?.documentType !== selectedDocument?.code); - if (uploadedFile?.length === 0 || uploadedFile === null) return filteredDocumentsByDocumentType; - const filteredDocumentsByFileStoreId = filteredDocumentsByDocumentType?.filter((item) => item?.fileStoreId !== uploadedFile); - return [ - ...filteredDocumentsByFileStoreId, - { - documentType: selectedDocument?.code, - fileStoreId: uploadedFile, - documentUid: uploadedFile, - fileName: file?.name || "", - id: documents ? documents.find(x => x.documentType === selectedDocument?.code)?.id : undefined, - }, - ]; - }); - } - }, [uploadedFile, selectedDocument]); - - useEffect(() => { - (async () => { - if (selectArrayFiles.length > 0) { - sessionStorage.removeItem("BPA_DOCUMENTS"); - doc.newUploadedDocs = []; - selectArrayFiles.map(newDoc => { - if (selectedDocument?.code) { - doc.newUploadedDocs.push({ - documentType: selectedDocument?.code, - fileStoreId: newDoc?.fileStoreId?.fileStoreId, - documentUid: newDoc?.fileStoreId?.fileStoreId, - tenantId: newDoc?.fileStoreId?.tenantId - }); - } - }) - bpaTaxDocuments[index] = doc; - sessionStorage.setItem("BPA_DOCUMENTS", JSON.stringify(bpaTaxDocuments)); - } - })(); - }, [selectArrayFiles, selectedDocument]); - - useEffect(() => { - (async () => { - - })(); - }, [file]); - - const getData = (index, state) => { - let data = Object.fromEntries(state); - let newArr = Object.values(data); - if (Object.keys(data).length !== 0) SetSelectArrayFiles(newArr); - selectfiles(newArr[newArr.length - 1]); - } - - return ( -
- {`${t(doc?.code)}`} - {doc?.uploadedDocuments?.length && } - { - checkEnablingDocs ? -
- - {doc?.required ? `${t(doc?.code)}* ` : `${t(doc?.code)}`} - - - - -
- getData(index, e)} - t={t} - allowedFileTypesRegex={allowedFileTypes} - allowedMaxSizeInMB={5} - acceptFiles= "image/*, .pdf, .png, .jpeg, .jpg" - /> -
-
-
: null - } -
- ); -} - -export default BPADocuments; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js deleted file mode 100644 index dfd57683def..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { CardSubHeader, PDFSvg } from "@egovernments/digit-ui-react-components"; - -function DocumentsPreview({ documents, svgStyles = {}, isSendBackFlow = false, isHrLine = false, titleStyles }) { - const { t } = useTranslation(); - const isStakeholderApplication = window.location.href.includes("stakeholder"); - - return ( -
- {!isStakeholderApplication && documents?.map((document, index) => ( - - {document?.title ? {t(document?.title)} : null} -
- {document?.values && document?.values.length > 0 ? document?.values?.map((value, index) => ( - -
- -
-

{t(value?.title)}

- {isSendBackFlow ? value?.documentType?.includes("NOC") ?

{t(value?.documentType.split(".")[1])}

:

{t(value?.documentType)}

: ""} -
- )) : !(window.location.href.includes("citizen")) &&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} -
- {isHrLine && documents?.length != index + 1 ?
: null} -
- ))} - {isStakeholderApplication && documents?.map((document, index) => ( - - {document?.title ? {t(document?.title)} : null} -
- {document?.values && document?.values.length > 0 ? document?.values?.map((value, index) => ( - -
-

{t(value?.title)}

- {value?.docInfo ?
{`${t(value?.docInfo)}`}
: null} - -

{`${t(value?.title)}`}

-
-
- )) : !(window.location.href.includes("citizen")) &&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} -
-
- ))} -
- ); -} - -export default DocumentsPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js deleted file mode 100644 index 12e2f64fac6..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from "react"; -import { InfoBannerIcon } from "@egovernments/digit-ui-react-components"; - -const EyeSvgINdex = ({ style }) => { - return - - - - - -} -const InfoDetails = ({ t, userType = false, infoBannerLabel = "", infoClickLable = "", infoClickInfoLabel = "", infoClickInfoLabel1 = "" }) => { - userType = userType || Digit.SessionStorage.get("userType"); - return ( - -
-
-
- -

{t(infoBannerLabel)}

-
- {`${t(infoClickLable)} `} - - {` ${t(infoClickInfoLabel)}`} -
- {` ${t(infoClickInfoLabel1)}`} -
-
-
-
- ); -}; - -export default InfoDetails; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js deleted file mode 100644 index a824b05a435..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js +++ /dev/null @@ -1,49 +0,0 @@ -import { StatusTable, Row, CardHeader, CardSectionHeader } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useTranslation } from "react-i18next"; -import DocumentsPreview from "./DocumentsPreview"; - -const getDocuments = (fiDocuments) => { - const returnDocuments = [{ - title: "BPA_DOCUMENT_DETAILS_LABEL", - values: fiDocuments?.map(doc => ({ - title: doc?.documentType?.replaceAll('.', '_'), - documentType: doc?.documentType, - documentUid: doc?.documentUid, - fileStoreId: doc?.fileStoreId, - id: doc?.id, - url: doc?.url - })) - }]; - return returnDocuments; -}; - -function InspectionReport({ fiReport, isCitizen=false }) { - const { t } = useTranslation(); - - return ( - -
- {isCitizen?{`${t(`BPA_FI_REPORT`)}`}: - {`${t(`BPA_FI_REPORT`)}`}} - {fiReport.map((fiData, index) => -
- - {fiReport?.length == 1 ? `${t(`BPA_FI_REPORT`)}` : `${t(`BPA_FI_REPORT`)} - ${index + 1}`} - - - {fiData?.questions?.length && - fiData?.questions?.map((qstn) => -
- - -
)} - -
-
)} -
-
- ); -} - -export default InspectionReport; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js deleted file mode 100644 index 1581744f756..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js +++ /dev/null @@ -1,202 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { - CardLabel, - MultiUploadWrapper, - StatusTable, - Row, - LabelFieldPair -} from "@egovernments/digit-ui-react-components"; -import DocumentsPreview from "./DocumentsPreview"; - -function SelectDocument({ - t, - document: doc, - setNocDocuments, - setError, - nocDocuments -}) { - const filteredDocument = nocDocuments?.filter((item) => item?.documentType?.includes(doc?.code))[0]; - const tenantId = Digit.ULBService.getStateId(); - const [selectedDocument, setSelectedDocument] = useState(); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(() => filteredDocument?.fileStoreId || null); - const handleSelectDocument = (value) => setSelectedDocument(value); - const allowedFileTypes = /(.*?)(jpg|jpeg|png|image|pdf)$/i; - - function selectfile(e) { - e && setFile(e.file); - } - - useEffect(() => { - if (doc?.dropdownData?.[0]?.code) { - setNocDocuments((prev) => { - const filteredDocumentsByDocumentType = prev?.filter((item) => item?.documentType !== doc?.dropdownData?.[0]?.code); - - if (uploadedFile?.length === 0 || uploadedFile === null) { - return filteredDocumentsByDocumentType; - } - - const filteredDocumentsByFileStoreId = filteredDocumentsByDocumentType?.filter((item) => item?.fileStoreId !== uploadedFile); - return [ - ...filteredDocumentsByFileStoreId, - { - documentType: doc?.dropdownData?.[0].code, - fileStoreId: uploadedFile, - documentUid: uploadedFile, - fileName: file?.name || "", - }, - ]; - }); - } - }, [uploadedFile]); - - - useEffect(() => { - (async () => { - setError(null); - if (file) { - const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { - setError(t(`NOT_SUPPORTED_FILE_TYPE`)) - } else { - try { - setUploadedFile(null); - const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - const getData =(state) => { - let data = Object.fromEntries(state); - let newArr = Object.values(data); - selectfile(newArr[newArr.length-1]); - } - - return ( -
- - {doc?.required ? `${t("TL_BUTTON_UPLOAD FILE")}*` : `${t("TL_BUTTON_UPLOAD FILE")}`} -
- getData(e)} - t={t} - allowedFileTypesRegex={allowedFileTypes} - allowedMaxSizeInMB={5} - acceptFiles="image/*, .pdf, .png, .jpeg, .jpg" - /> -
-
-
- ); -} -const NOCDocuments = ({ t, noc, docs, isNoc, applicationData,NOCdata, bpaActionsDetails }) => { - const tenantId = Digit.ULBService.getStateId(); - const stateId = Digit.ULBService.getStateId(); - const bpaApplicationStatus = applicationData?.status || ""; - const actions = bpaActionsDetails?.data?.nextActions || []; - const { isLoading: nocDocsLoading, data: nocDocs } = Digit.Hooks.obps.useMDMS(stateId, "NOC", ["DocumentTypeMapping"], { enabled: isNoc }); - const { isLoading: bpaDocsLoading, data: bpaDocs } = Digit.Hooks.obps.useMDMS(stateId, "BPA", ["DocTypeMapping"], { enabled: !isNoc }); - const { isLoading: commonDocsLoading, data: commonDocs } = Digit.Hooks.obps.useMDMS(stateId, "common-masters", ["DocumentType"]); - const [commonDocMaping, setCommonDocMaping] = useState([]); - const [nocTaxDocuments, setNocTaxDocuments] = useState([]); - const [checkEnablingDocs, setCheckEnablingDocs] = useState(false); - const [nocDocuments, setNocDocuments] = Digit.Hooks.useSessionStorage(noc?.nocType, []); - const [error, setError] = useState(null); - const isEmployee = window.location.href.includes("/employee/") - - useEffect(() => { - setCommonDocMaping(commonDocs?.["common-masters"]?.DocumentType); - }, [commonDocs]); - - useEffect(() => { - let documents = []; - let filteredData - if (isNoc) { - filteredData = nocDocs?.NOC?.DocumentTypeMapping?.filter((data => { - return data?.applicationType === noc?.applicationType && data?.nocType === noc?.nocType - })); - } - else { - filteredData = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == applicationData?.status && data.RiskType == applicationData?.riskType && data.ServiceType == applicationData?.additionalDetails?.serviceType && data.applicationType == applicationData?.additionalDetails?.applicationType)) - } - if (filteredData?.[0]?.docTypes?.[0]) { - filteredData[0].docTypes[0].nocType = filteredData[0].nocType; - filteredData[0].docTypes[0].additionalDetails = { - submissionDetails: noc?.additionalDetails, - applicationStatus: noc?.applicationStatus, - appNumberLink: noc?.applicationNo, - nocNo: noc?.nocNo - } - documents.push(filteredData[0].docTypes[0]); - } - let documentsList = []; - if (documents && documents.length > 0) { - documents.map((doc) => { - let code = doc.documentType; - let nocType = doc.nocType; - doc.dropdownData = []; - commonDocMaping?.forEach((value) => { - let values = value.code.slice(0, code?.length); - if (code === values) { - doc.hasDropdown = true; - doc.dropdownData.push(value); - } - }); - documentsList.push(doc); - }); - setNocTaxDocuments(documentsList); - } - }, [nocDocs, commonDocMaping]); - - useEffect(() => { - if (bpaApplicationStatus === 'NOC_VERIFICATION_INPROGRESS' && actions?.length > 0) setCheckEnablingDocs(true); - else setCheckEnablingDocs(false); - }, [applicationData, bpaActionsDetails]) - - return ( -
- - - {NOCdata && NOCdata.map((noc,index) => { - if (noc?.value) { - if (noc?.field == "STATUS") { - return - } else { - return - } - } - })} - - - {checkEnablingDocs && nocTaxDocuments?.map((document, index) => { - return ( - - ); - })} -
- ); -} - -export default NOCDocuments; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js deleted file mode 100644 index 89007789722..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js +++ /dev/null @@ -1,87 +0,0 @@ -import { CheckBox, LinkButton, TextInput,Close, CardSubHeader } from "@egovernments/digit-ui-react-components"; -import React, { useEffect, useState } from "react"; - -const PermissionCheck = ({ permissions, t }) => { - const [approvalChecks, setApprovalChecks, clearApprovals] = Digit.Hooks.useSessionStorage("OBPS_APPROVAL_CHECKS", permissions?.map(permission => ({ label: permission, checked: false }))); //useState(() => permissions?.map(permission => ({ label: permission, checked: false }))) - const [newApprovals, setNewApprovals, clearNewApprovals] = Digit.Hooks.useSessionStorage('OBPS_NEW_APPROVALS', []); - - useEffect(() => { - return () => { - Digit.SessionStorage.del("OBPS_NEW_APPROVALS"); - Digit.SessionStorage.del("OBPS_APPROVAL_CHECKS"); - } - }, []) - - const handleAdd = () => { - setNewApprovals([...newApprovals, { label: '' }]); - } - - const handleRemove = (index) => { - const values = [...newApprovals]; - values.splice(index, 1); - setNewApprovals([...values]); - } - - const handleChange = (event, index) => { - setNewApprovals(() => { - return newApprovals?.map((approval, id) => { - if (index === id) { - return { - label: event?.target?.value, - } - } - return approval; - }) - }) - } - - const handleCheck = (event, label, index) => { - const isChecked = event.target.checked; - setApprovalChecks(() => { - return approvalChecks?.map((approval, id) => { - if (index === id) { - return { - ...approval, - checked: isChecked - } - } - return approval; - }) - }) - } - - return ( -
- {t("BPA_PERMIT_CONDITIONS")} - {approvalChecks?.map((permission, index) => ( - handleCheck(event, permission?.label, index))} - isLabelFirst={true} - index={index} - /> - ))} - {newApprovals?.map((approval, index) => ( -
handleChange(event, index)} textInputStyle={{maxWidth: "830px", width: "830px"}} placeholder={"Enter permit conditions.........."} /> - { - - - -
- } - style={{ }} - onClick={(e) => handleRemove(index)} - />} -
- ))} - -
- ) -} - -export default PermissionCheck; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js deleted file mode 100644 index ea8cd1eb104..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js +++ /dev/null @@ -1,83 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { CardSubHeader, PDFSvg } from "@egovernments/digit-ui-react-components"; - -// const PDFSvg = ({ width = 34, height = 34, style, viewBox = "0 0 34 34" }) => ( -// -// -// -// ); - -function PropertyDocuments({ documents, svgStyles = {}, isSendBackFlow=false }) { - const { t } = useTranslation(); - const [filesArray, setFilesArray] = useState(() => [] ); - const tenantId = Digit.ULBService.getCurrentTenantId(); - const [pdfFiles, setPdfFiles] = useState({}); - - useEffect(() => { - let acc = []; - documents?.forEach((element, index, array) => { - acc = [...acc, ...(element.values?element.values:[])]; - }); - setFilesArray(acc?.map((value) => value?.fileStoreId)); - }, [documents]); - - useEffect(() => { - if (filesArray?.length && documents?.[0]?.BS === "BillAmend") { - Digit.UploadServices.Filefetch(filesArray, Digit.ULBService.getCurrentTenantId()).then((res) => { - setPdfFiles(res?.data); - }); - } - else if(filesArray?.length) - { - Digit.UploadServices.Filefetch(filesArray, Digit.ULBService.getStateId()).then((res) => { - setPdfFiles(res?.data); - }); - } - - }, [filesArray]); - - const checkLocation = window.location.href.includes("employee/tl") || window.location.href.includes("/obps") || window.location.href.includes("employee/ws"); - const isStakeholderApplication = window.location.href.includes("stakeholder"); - - return ( -
- {!isStakeholderApplication && documents?.map((document, index) => ( - - {document?.title ? {t(document?.title)}: null} -
- {document?.values && document?.values.length>0 ? document?.values?.map((value, index) => ( - -
- -
-

{t(value?.title)}

- {isSendBackFlow? value?.documentType?.includes("NOC")?

{t(value?.documentType.split(".")[1])}

:

{t(value?.documentType)}

:""} -
- )):!(window.location.href.includes("citizen"))&&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} -
-
- ))} - {isStakeholderApplication && documents?.map((document, index) => ( - - {document?.title ? {t(document?.title)} : null} -
- {document?.values && document?.values.length>0 ? document?.values?.map((value, index) => ( - -
-

{t(value?.title)}

- {value?.docInfo ?
{`${t(value?.docInfo)}`}
: null} - - {/*
{decodeURIComponent(pdfFiles[value.fileStoreId]?.split(",")[0].split("?")[0].split("/").pop().slice(13))}
*/} -

{`${t(value?.title)}`}

-
-
- )):!(window.location.href.includes("citizen"))&&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} -
-
- ))} -
- ); -} - -export default PropertyDocuments; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js deleted file mode 100644 index c4cde76709f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js +++ /dev/null @@ -1,39 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { StatusTable, Row, BreakLine } from "@egovernments/digit-ui-react-components"; - -function PropertyEstimates({ taxHeadEstimatesCalculation }) { - const { taxHeadEstimates } = taxHeadEstimatesCalculation; - const { t } = useTranslation(); - - return ( -
- - - - {taxHeadEstimates?.map((estimate, index) => { - return ( - - ); - })} - - - -
- ); -} - -export default PropertyEstimates; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js deleted file mode 100644 index 4f33bbdcff4..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; - -function PropertyFloors({ floors }) { - const { t } = useTranslation(); - - return ( - - {floors.map((floor) => ( -
- {t(floor?.title)} - {floor?.values?.map((value, index) => { - return ( - - - {t(value.title)} - - -
- {value?.values?.map((value, index) => { - if (value.map === true && value.value !== "N/A") { - return } />; - } - return ( - - ); - })} -
-
-
- ); - })} -
- ))} -
- ); -} - -export default PropertyFloors; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js deleted file mode 100644 index dac9f41c79b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js +++ /dev/null @@ -1,94 +0,0 @@ -import { CardSubHeader, Row, StatusTable } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useTranslation } from "react-i18next"; - -function PropertyOwners({ owners }) { - const { t } = useTranslation(); - - const checkLocation = true; - const checkOwnerLength = owners?.length || 1; - let cardStyles = { marginTop: "19px" }; - let statusTableStyles = { position: "relative", padding: "8px" }; - let rowContainerStyle = { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; - if (checkLocation && Number(checkOwnerLength) > 1) { - cardStyles = { - marginTop: "19px", - background: "#FAFAFA", - border: "1px solid #D6D5D4", - borderRadius: "4px", - padding: "8px", - lineHeight: "19px", - maxWidth: "600px", - minWidth: "280px", - }; - } else if (checkLocation && !(Number(checkOwnerLength) > 1)) { - cardStyles = { marginTop: "19px", lineHeight: "19px", maxWidth: "600px", minWidth: "280px" }; - statusTableStyles = { position: "relative", marginTop: "19px" }; - } - - if (window.location.href.includes("obps")) { - cardStyles = { ...cardStyles, maxWidth: "950px" }; - cardStyles = { ...cardStyles, maxWidth: "950px" }; - rowContainerStyle = {}; - } - - return ( - - {owners.map((owner, index) => ( -
- {/* TODO, Later will move to classes */} - 1 - ? { marginBottom: "8px", paddingBottom: "9px", color: "#0B0C0C", fontSize: "16px", lineHeight: "19px" } - : { marginBottom: "8px", color: "#505A5F", fontSize: "24px" } - } - > - {checkLocation && Number(checkOwnerLength) > 1 ? `${t(owner?.title)} ${index + 1}` : t(owner?.title)} - - - -
- {owner?.values?.map((value, index) => { - if (value.map === true && value.value !== "N/A") { - return } />; - } - return ( - - - - ); - })} -
-
-
- ))} -
- ); -} - -export default PropertyOwners; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js deleted file mode 100644 index 0f226935c5b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from "react"; - -const Reason = ({ headComment, otherComment }) => ( -
-

{headComment}

-

{otherComment}

-
-); - -export default Reason; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js deleted file mode 100644 index bde27623ba8..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js +++ /dev/null @@ -1,46 +0,0 @@ -import { StatusTable, Row, PDFSvg, CardLabel, CardSubHeader } from "@egovernments/digit-ui-react-components"; -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; - -const ScruntinyDetails = ({ scrutinyDetails, paymentsList=[] }) => { - const { t } = useTranslation(); - let count = 0; - const getTextValues = (data) => { - if (data?.value && data?.isTransLate) return {t(data?.value)}; - else if (data?.value && data?.isTransLate) return t(data?.value); - else if (data?.value) return data?.value; - else t("NA"); - } - return ( - - {!scrutinyDetails?.isChecklist &&
- -
- {scrutinyDetails?.values?.map((value, index) => { - if (value?.isUnit) return - else if (value?.isHeader && !value?.isUnit) return {t(value?.title)} - else if (value?.isSubTitle && !value?.isUnit) return {t(value?.title)} - else return - })} - {scrutinyDetails?.permit?.map((value,ind) => { - return {value?.title} - })} -
-
- {scrutinyDetails?.scruntinyDetails?.map((report, index) => { - return ( - - - -

{t(report?.text)}

-
- ) - })} -
-
-
} -
- ) -} - -export default ScruntinyDetails; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js deleted file mode 100644 index e266bed6be2..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js +++ /dev/null @@ -1,126 +0,0 @@ -import React, { Fragment, useMemo } from "react"; -import { Table, StatusTable, Row, CardSubHeader, CardSectionHeader } from "@egovernments/digit-ui-react-components"; -import { useTranslation } from "react-i18next"; - -const SubOccupancyTable = ({ edcrDetails, applicationData }) => { - const { t } = useTranslation(); - const isMobile = window.Digit.Utils.browser.isMobile(); - - const tableHeader = [ - { - name: "BPA_TABLE_COL_FLOOR", - id: "Floor", - }, - { - name: "BPA_TABLE_COL_LEVEL", - id: "Level", - }, - { - name: "BPA_TABLE_COL_OCCUPANCY", - id: "Occupancy", - }, - { - name: "BPA_TABLE_COL_BUILDUPAREA", - id: "BuildupArea", - }, - { - name: "BPA_TABLE_COL_FLOORAREA", - id: "FloorArea", - }, - { - name: "BPA_TABLE_COL_CARPETAREA", - id: "CarpetArea", - } - ] - - const accessData = (plot) => { - const name = plot; - return (originalRow, rowIndex, columns) => { - return originalRow[name]; - } - } - - - const tableColumns = useMemo( - () => { - return tableHeader.map((ob) => ({ - Header: t(`${ob.name}`), - accessor: accessData(ob.id), - id: ob.id - })); - }); - - function getFloorData(block) { - let floors = []; - block?.building?.floors.map((ob) => { - floors.push({ - Floor: t(`BPA_FLOOR_NAME_${ob.number}`), - Level: ob.number, - Occupancy: t(`${ob.occupancies?.[0]?.type}`), - BuildupArea: ob.occupancies?.[0]?.builtUpArea, - FloorArea: ob.occupancies?.[0]?.floorArea || 0, - CarpetArea: ob.occupancies?.[0]?.CarpetArea || 0, - key: t(`BPA_FLOOR_NAME_${ob.number}`), - }); - }); - return floors; - } - - const stringReplaceAll = (str = "", searcher = "", replaceWith = "") => { - if (searcher == "") return str; - while (str.includes(searcher)) { - str = str.replace(searcher, replaceWith); - } - return str; - }; - - function getSubOccupancyValues(index) { - let values = applicationData?.landInfo?.unit; - let returnValue = ""; - if (values?.length > 0) { - let splitArray = values[index]?.usageCategory?.split(','); - if (splitArray?.length) { - const returnValueArray = splitArray.map(data => data ? `${t(`BPA_SUBOCCUPANCYTYPE_${stringReplaceAll(data?.toUpperCase(), "-", "_")}`)}` : "NA"); - returnValue = returnValueArray.join(', ') - } - } - return returnValue ? returnValue : "NA"; - } - - return ( - -
- - {edcrDetails?.values?.map((value, index) => { - if (value?.isHeader) return {t(value?.title)} - else return - })} - - - {edcrDetails?.subOccupancyTableDetails?.[0]?.value?.planDetail?.blocks.map((block, index) => ( -
0 ? {marginBottom: "30px", background: "#FAFAFA", border: "1px solid #D6D5D4", padding: "8px", borderRadius: "4px", maxWidth: "950px", minWidth: "280px"} : {marginBottom: "30px"}}> - {t("BPA_BLOCK_SUBHEADER")} {index + 1} - - - -
- { return { style: {} } }} - /> - - ))} - - - ) -} - -export default SubOccupancyTable; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js deleted file mode 100644 index 08b89e68419..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js +++ /dev/null @@ -1,77 +0,0 @@ -import { EditIcon } from '@egovernments/digit-ui-react-components'; -import React from 'react' -import { useTranslation } from "react-i18next"; -import { useHistory } from 'react-router-dom'; - -const SubWorkTableDetails = ({data}) => { - const { t } = useTranslation(); - const history = useHistory(); - const getStyles = (index) => { - let obj = {} - switch (index) { - case 1: - obj = { "width": "1vw" } - break; - case 2: - obj = { "width": "60vw" } - break; - case 3: - obj = { "width": "20vw" } - break; - case 4: - obj = { "width": "10vw" } - break; - default: - obj = { "width": "1vw" } - break; - } - return obj - } - const renderHeader = (headers) => { - return headers?.map((key, index) => { - return - }) - } - - const renderBody = (rows) => { - return rows?.map((row, index) => { - return - - - {row[1] === t("WORKS_TOTAL_AMT") - ? - : } - {row[3] && } - {/* */} - - }) - } - - return ( -
{t(key)}
{row[0]} { row[1] === t("WORKS_TOTAL_AMT") ?
{row[1]}
:
{row[1]}
}
{row[2]}
{row[2]}
-
history.push( - { - pathname: `/digit-ui/employee/contracts/create-contract?estimateNumber=${data?.state?.estimateNumber}&task=${data?.state?.estimateDetails[index]?.name}&subEstimate=${data?.state?.estimateDetails[index]?.estimateDetailNumber}`, - state:{index, data} - } - )}> - {row[3]} -
-
{showDelete() && removeRow(row)}>}
- - {renderHeader(data?.headers)} - - - {renderBody(data?.tableRows)} - {/* - - - - - */} - -
- ) -} - -export default SubWorkTableDetails \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js deleted file mode 100644 index e5fbcde20cd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { TelePhone, DisplayPhotos, UnMaskComponent } from "@egovernments/digit-ui-react-components"; -import Reason from "./Reason"; - -const TLCaption = ({ data,OpenImage,privacy={}}) => { - - const { t } = useTranslation(); - return ( -
- {data.date &&

{data.date}

} -

{data.name}

- {data.mobileNumber && - -

    

- -
} - {data.source &&

{t("ES_APPLICATION_DETAILS_APPLICATION_CHANNEL_" + data.source.toUpperCase())}

} - {data.comment && } - {data?.wfComment ?
{data?.wfComment?.map( e => -
-

{t("WF_COMMON_COMMENTS")}

-

{e}

-
- )}
: null} - {data?.thumbnailsToShow?.thumbs?.length > 0 ?
-

{t("CS_COMMON_ATTACHMENTS")}

- {OpenImage(src, index,data?.thumbnailsToShow)}} /> -
: null} -
- ); -}; - -export default TLCaption; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js deleted file mode 100644 index 536a2ce3eca..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js +++ /dev/null @@ -1,52 +0,0 @@ - -import React from "react"; -import { useTranslation } from "react-i18next"; -import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; - -function TLTradeAccessories({ units }) { - const { t } = useTranslation(); - return ( - - {units.map((unit, index) => ( - // TODO, Later will move to classes -
- {`${t(unit?.title)} ${index + 1}`} - - -
- {unit?.values?.map((value, index) => { - if (value.map === true && value.value !== "N/A") { - return } />; - } - return ( - - ); - })} -
-
-
- ))} -
- ); -} - -export default TLTradeAccessories; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js deleted file mode 100644 index bf1c1fbc780..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; - -function TLTradeUnits({ units }) { - const { t } = useTranslation(); - return ( - - {units.map((unit, index) => ( - // TODO, Later will move to classes -
- {`${t(unit?.title)} ${index + 1}`} - - -
- {unit?.values?.map((value, index) => { - if (value.map === true && value.value !== "N/A") { - return } />; - } - return ( - - ); - })} -
-
-
- ))} -
- ); -} - -export default TLTradeUnits; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js deleted file mode 100644 index 5608aeb2d2a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js +++ /dev/null @@ -1,73 +0,0 @@ -import React, { useState, Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { CardSectionHeader, Modal, Row, StatusTable } from "@egovernments/digit-ui-react-components"; - -const ViewBreakup = ({ wsAdditionalDetails, workflowDetails }) => { - const { t } = useTranslation(); - const [popup, showPopUp] = useState(false); - const [breakUpData, setBreakUpData] = useState({}); - - const Heading = (props) => { - return

{props.label}

; - }; - - const Close = () => ( - - - - - ); - - const CloseBtn = (props) => { - return ( -
- -
- ); - }; - - const onPopupOpen = () => { - let breakupData = wsAdditionalDetails.additionalDetails.data || {}; - const sessionBillData = sessionStorage.getItem("Digit.ADHOC_BILL_ADD_REBATE_DATA"); - const sessionBillFormData = sessionBillData ? JSON.parse(sessionBillData) : {}; - if (sessionBillFormData?.value?.totalAmount) breakupData = sessionBillFormData?.value; - setBreakUpData(breakupData); - showPopUp(true); - } - - return ( - -
- {wsAdditionalDetails?.additionalDetails?.isViewBreakup ?
onPopupOpen()} style={{ marginTop: "12px" }}> - {t("WS_PAYMENT_VIEW_BREAKUP")} -
: null - } - {popup && - } - headerBarEnd={ { showPopUp(false); }} />} - hideSubmit={true} - popupStyles={{ overflowY: "auto" }} //maxHeight: "calc(100% - 90px)" - headerBarMainStyle={{ marginBottom: "0px" }} - popupModuleMianStyles={{ paddingTop: "0px" }} - > - { - {t("WS_APPLICATION_FEE_HEADER")} - {breakUpData?.billSlabData?.FEE?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} -
- ₹{Number(breakUpData?.fee) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> - {t("WS_SERVICE_FEE_HEADER")} - {breakUpData?.billSlabData?.CHARGES?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} -
- ₹{Number(breakUpData?.charge) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> - {breakUpData?.billSlabData?.TAX?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} -
- ₹{Number(breakUpData?.totalAmount) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> -
} -
} -
-
- ) -} - -export default ViewBreakup; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js deleted file mode 100644 index 06814062d96..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js +++ /dev/null @@ -1,399 +0,0 @@ -import { StatusTable, Row, CardSubHeader } from "@egovernments/digit-ui-react-components"; -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { getQueryStringParams } from "../../../ws/src/utils"; - -const cardSubHeaderStyles = () => { - // return { fontSize: "24px", padding: "0px", margin: "0px", color: "#505A5F" }; - return { fontSize: "24px", marginBottom: "16px", marginTop: "32px" }; -}; - -const cardDivStyles = () => { - return { - border: "1px solid #D6D5D4", - background: "#FAFAFA", - borderRadius: "4px", - padding: "10px 10px 0px 10px", - marginBottom: "10px", - display: "flex", - }; -}; - -const convertEpochToDate = (dateEpoch) => { - if (dateEpoch) { - const dateFromApi = new Date(dateEpoch); - let month = dateFromApi.getMonth() + 1; - let day = dateFromApi.getDate(); - let year = dateFromApi.getFullYear(); - month = (month > 9 ? "" : "0") + month; - day = (day > 9 ? "" : "0") + day; - return `${day}/${month}/${year}`; - } else { - return null; - } -}; - -const WSAdditonalDetails = ({ wsAdditionalDetails, oldValue }) => { - const { t } = useTranslation(); - let filters = getQueryStringParams(location.search); - const serviceType = filters?.service; - const isModify = filters?.mode; - - const oldValueData = oldValue?.[1]; - - const stringReplaceAll = (str = "", searcher = "", replaceWith = "") => { - if (searcher == "") return str; - while (str.includes(searcher)) { - str = str.replace(searcher, replaceWith); - } - return str; - }; - - const renderSWConnectionDetails = () => { - return ( -
- {oldValueData?.connectionType ? ( - - ) : ( -
{"NA"}
- )} - - {oldValueData?.noOfWaterClosets ? ( - - ) : ( -
{"NA"}
- )} - {oldValueData?.noOfToilets ? ( - - ) : ( -
{"NA"}
- )} -
- ); - }; - - const renderWSConnectionDetails = () => { - return ( -
- {oldValueData?.connectionType && ( )} - {oldValueData?.noOfTaps && ( )} - {oldValueData?.waterSource && ( )} - {oldValueData?.pipeSize && ( )} - {oldValueData?.waterSource && ( )} -
- ); - }; - - const renderSWPlumberDetails = () => { - return ( -
- {oldValueData?.additionalDetails?.detailsProvidedBy !== wsAdditionalDetails?.additionalDetails?.plumberDetails[0]?.value && - oldValueData?.additionalDetails?.detailsProvidedBy !== null ? ( - - ) : ( -
{"NA"}
- )} - {oldValueData?.plumberInfo ? ( - - ) : ( -
{"NA"}
- )} - {oldValueData?.plumberInfo ? ( - - ) : ( -
{"NA"}
- )} - {oldValueData?.plumberInfo ? ( - - ) : ( -
{"NA"}
- )} -
- ); - }; - - const renderWSPlumberDetails = () => { - return ( -
- {oldValueData?.additionalDetails?.detailsProvidedBy !== wsAdditionalDetails?.additionalDetails?.plumberDetails[0]?.value ? ( - - ) : ( -
{"NA"}
- )} -
- ); - }; - - const renderSWRoadCuttingDetails = () => { - { - oldValueData?.roadCuttingInfo?.map((info) => { - return ( -
- - -
- ); - }); - } - }; - - const renderSWActivationDetails = () => { - return ( -
- {oldValueData?.connectionExecutionDate ? ( - - ) : ( -
{"NA"}
- )} -
- ); - }; - - const renderWSActivationDetails = () => { - return ( -
- {oldValueData?.meterId && ( )} - {oldValueData?.additionalDetails?.initialMeterReading && ( )} - {oldValueData?.meterInstallationDate && ( )} - {oldValueData?.connectionExecutionDate && ( )} -
- ); - }; - - var { connectionDetails, plumberDetails, roadCuttingDetails, activationDetails } = wsAdditionalDetails?.additionalDetails || {connectionDetails:[], plumberDetails: []}; - - // binding old values with new values - if(isModify === "MODIFY"){ - - connectionDetails = connectionDetails?.map((value) => { - if(value.title == "WS_SERV_DETAIL_CONN_TYPE" && oldValueData?.connectionType) value["oldValue"] = [ - { value:value?.value, className:"newValue", style:{ display:"inline"} }, - { - value:`${t("WS_OLD_LABEL_NAME")} ${oldValueData?.connectionType}`, - className:"oldValue", style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"} - }]; - if(value.title == "WS_SERV_DETAIL_NO_OF_TAPS" && oldValueData?.noOfTaps) value["oldValue"] = [ - {value:value?.value,className:"newValue", style:{ display:"inline"}}, - {value:`${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfTaps}`, style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"},className:"oldValue"} - ]; - if(value.title == "WS_SERV_DETAIL_WATER_SOURCE" && oldValueData?.waterSource) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${t(oldValueData?.waterSource?.toUpperCase()?.split(".")[0])}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_PIPE_SIZE_IN_INCHES_LABEL" && oldValueData?.pipeSize) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.pipeSize}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_SERV_DETAIL_WATER_SUB_SOURCE" && oldValueData?.waterSource) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${t(oldValueData?.waterSource?.toUpperCase()?.split(".")[1])}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_NUMBER_WATER_CLOSETS_LABEL" && oldValueData?.noOfWaterClosets) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfWaterClosets}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_SERV_DETAIL_NO_OF_TOILETS" && oldValueData?.noOfWaterClosets) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfWaterClosets}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - - return value; - }) - - plumberDetails = plumberDetails?.map((value) => { - if(value.title == "WS_ADDN_DETAILS_PLUMBER_PROVIDED_BY" && oldValueData?.additionalDetails?.detailsProvidedBy && oldValueData?.additionalDetails?.detailsProvidedBy !== value.value ) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.additionalDetails?.detailsProvidedBy}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_ADDN_DETAILS_PLUMBER_LICENCE_NO_LABEL" && oldValueData?.plumberInfo[0]?.licenseNo ) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.licenseNo}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_ADDN_DETAILS_PLUMBER_NAME_LABEL" && oldValueData?.plumberInfo[0]?.name ) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.name}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_PLUMBER_MOBILE_NO_LABEL" && oldValueData?.plumberInfo[0]?.mobileNumber ) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.mobileNumber}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - return value; - }) - - roadCuttingDetails = roadCuttingDetails?.map((roadDetail) => { - const roadDetailValues = roadDetail?.values?.map((value) => { - if(value.title == "WS_ADDN_DETAIL_ROAD_TYPE" && oldValueData?.roadCuttingInfo[0]?.roadType) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.roadCuttingInfo[0]?.roadType}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_ROAD_CUTTING_AREA_LABEL" && oldValueData?.roadCuttingInfo[0]?.roadCuttingArea) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.roadCuttingInfo[0]?.roadCuttingArea}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - return value; - }) - return ({...roadDetail,values:roadDetailValues}); - }) - - activationDetails = activationDetails?.map((value) => { - if(value.title == "WS_SERV_DETAIL_CONN_EXECUTION_DATE" && oldValueData?.connectionExecutionDate) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.connectionExecutionDate)}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - - if(value.title == "WS_SERV_DETAIL_METER_ID" && oldValueData?.meterId) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.meterId}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - - if(value.title == "WS_INITIAL_METER_READING_LABEL" && oldValueData?.initialMeterReading) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.initialMeterReading}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - - if(value.title == "WS_INSTALLATION_DATE_LABEL" && oldValueData?.meterInstallationDate) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.meterInstallationDate)}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_SERV_DETAIL_CONN_EXECUTION_DATE" && oldValueData?.connectionExecutionDate) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.connectionExecutionDate)}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - return value; - }) - }; - - return ( - -
- {wsAdditionalDetails?.additionalDetails?.connectionDetails && ( - - {t("WS_COMMON_CONNECTION_DETAIL")} -
-
- {connectionDetails?.map((value, index) => { - return ( -
- -
- ); - })} -
-
-
- )} - {wsAdditionalDetails?.additionalDetails?.plumberDetails && ( - - {t("WS_COMMON_PLUMBER_DETAILS")} -
-
- - {plumberDetails?.map((value, index) => { - return ; - })} -
-
-
- )} - {wsAdditionalDetails?.additionalDetails?.roadCuttingDetails && ( - - {t("WS_ROAD_CUTTING_DETAILS")} -
-
- {roadCuttingDetails?.map((value) => { - return ( -
1 - ? { - border: "1px solid #D6D5D4", - background: "#FAFAFA", - borderRadius: "4px", - padding: "10px 10px 0px 10px", - margin: "5px 0px", - } - : {} - } - > - {value?.values?.map((roadValue) => ( - - ))} -
- ); - })} -
-
-
- )} - {wsAdditionalDetails?.additionalDetails?.activationDetails && ( - - {t("WS_ACTIVATION_DETAILS")} -
-
- {activationDetails?.map((value, index) => { - return ( - - ); - })} -
-
-
- )} -
-
- ); -}; - -export default WSAdditonalDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js deleted file mode 100644 index 9a4fe591f9d..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js +++ /dev/null @@ -1,346 +0,0 @@ -import React, { useState, Fragment, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { Card, CardSectionHeader, CardLabel } from "@egovernments/digit-ui-react-components"; -import { Modal, Dropdown, Row, StatusTable, TextInput, Toast } from "@egovernments/digit-ui-react-components"; -import cloneDeep from "lodash/cloneDeep"; - -const Penality_menu = [ - { - title: "PT_PENDING_DUES_FROM_EARLIER", - value: "Pending dues from earlier", - }, - { - title: "PT_MISCALCULATION_OF_EARLIER_ASSESSMENT", - value: "Miscalculation of earlier Assessment", - }, - { - title: "PT_ONE_TIME_PENALITY", - value: "One time penality", - }, - { - title: "PT_OTHERS", - value: "Others", - }, -] -const Rebate_menu = [ - { - title: "PT_ADVANCED_PAID_BY_CITIZEN_EARLIER", - value: "Advanced Paid By Citizen Earlier", - }, - { - title: "PT_REBATE_PROVIDED_BY_COMMISSIONER_EO", - value: "Rebate provided by commissioner/EO", - }, - { - title: "PT_ADDITIONAL_AMOUNT_CHARGED_FROM_THE_CITIZEN", - value: "Additional amount charged from the citizen", - }, - { - title: "PT_OTHERS", - value: "Others", - }, -]; - - -const WSFeeEstimation = ({ wsAdditionalDetails, workflowDetails }) => { - const { t } = useTranslation(); - const [sessionFormData, setSessionFormData, clearSessionFormData] = Digit.Hooks.useSessionStorage("ADHOC_ADD_REBATE_DATA", {}); - const [sessionBillFormData, setSessionBillFormData, clearBillSessionFormData] = Digit.Hooks.useSessionStorage("ADHOC_BILL_ADD_REBATE_DATA", {}); - const isPaid = wsAdditionalDetails?.additionalDetails?.isPaid ? true : false; - const [popup, showPopUp] = useState(false); - const [fields, setFields] = useState(sessionFormData ? sessionFormData : {}); - const [showToast, setShowToast] = useState(null); - const [billDetails, setBillDetails] = useState(wsAdditionalDetails.additionalDetails.data ? wsAdditionalDetails.additionalDetails.data : {}); - const [values, setValues] = useState(wsAdditionalDetails.additionalDetails.values ? wsAdditionalDetails.additionalDetails.values : []); - - const stateCode = Digit.ULBService.getStateId(); - const { isMdmsLoading, data: mdmsRes } = Digit.Hooks.ws.useMDMS(stateCode, "BillingService", ["TaxHeadMaster"]); - - useEffect(() => { - const data = { ...wsAdditionalDetails?.additionalDetails?.appDetails?.additionalDetails }; - setSessionFormData(data); - setFields(data); - if (sessionFormData?.billDetails?.length > 0) { - const values = [ - { title: "WS_APPLICATION_FEE_HEADER", value: sessionFormData?.billDetails?.[0]?.fee }, - { title: "WS_SERVICE_FEE_HEADER", value: sessionFormData?.billDetails?.[0]?.charge }, - { title: "WS_TAX_HEADER", value: sessionFormData?.billDetails?.[0]?.taxAmount }, - ]; - setValues(values); - setBillDetails(sessionFormData?.billDetails?.[0]); - } - }, []); - - let validation = {}; - - const Heading = (props) => { - return

{props.label}

; - }; - - const Close = () => ( - - - - - ); - - const CloseBtn = (props) => { - return ( -
- -
- ); - }; - - const closeToast = () => { - setShowToast(false); - }; - - const addAdhocRebatePenality = (e) => { - const adhocAmount = fields?.adhocPenalty ? Number(fields?.adhocPenalty) : 0; - const rebateAmount = fields?.adhocRebate ? Number(fields?.adhocRebate) : 0; - if (adhocAmount || rebateAmount) { - - const totalAmount = wsAdditionalDetails?.additionalDetails?.data?.totalAmount; - const demandId = wsAdditionalDetails?.additionalDetails?.data?.billDetails?.[0]?.demandId; - - if (rebateAmount > totalAmount) { - setShowToast({ isError: false, isWarning: true, key: "error", message: t("ERR_WS_REBATE_GREATER_THAN_AMOUNT") }); - } else { - const applicationNo = wsAdditionalDetails?.additionalDetails?.appDetails?.applicationNo; - const tenantId = wsAdditionalDetails?.additionalDetails?.appDetails?.tenantId; - const appAdditionalDetails = { ...wsAdditionalDetails?.additionalDetails?.appDetails?.additionalDetails, ...fields } - wsAdditionalDetails.additionalDetails.appDetails.additionalDetails = appAdditionalDetails; - - const data = { - CalculationCriteria: - wsAdditionalDetails?.additionalDetails?.appDetails?.service == "WATER" - ? [ - { - applicationNo: applicationNo, - tenantId: tenantId, - waterConnection: wsAdditionalDetails.additionalDetails.appDetails, - }, - ] - : [ - { - applicationNo: applicationNo, - tenantId: tenantId, - sewerageConnection: wsAdditionalDetails.additionalDetails.appDetails, - }, - ], - isconnectionCalculation: false, - }; - - let businessService = wsAdditionalDetails?.additionalDetails?.appDetails?.service == "WATER" ? "WS" : "SW"; - Digit.WSService.wsCalculationEstimate(data, businessService) - .then((result, err) => { - if (result?.Calculation?.[0]?.taxHeadEstimates?.length > 0) { - result?.Calculation?.[0]?.taxHeadEstimates?.forEach(data => data.amount = data.estimateAmount); - } - - result.Calculation[0].billSlabData = _.groupBy(result?.Calculation?.[0]?.taxHeadEstimates, 'category'); - const values = [ - { title: "WS_APPLICATION_FEE_HEADER", value: result.Calculation?.[0]?.fee }, - { title: "WS_SERVICE_FEE_HEADER", value: result.Calculation?.[0]?.charge }, - { title: "WS_TAX_HEADER", value: result.Calculation?.[0]?.taxAmount }, - ]; - setSessionBillFormData(cloneDeep(result.Calculation[0])); - setBillDetails(result?.Calculation?.[0]); - setValues(values); - fields.billDetails = result?.Calculation; - setSessionFormData(fields); - showPopUp(false); - }) - .catch((e) => { - setShowToast({ isError: true, isWarning: false, key: "error", message: e?.response?.data?.Errors[0]?.message ? t(`${e?.response?.data?.Errors[0]?.code}`) : t("PT_COMMON_ADD_REBATE_PENALITY") }); - }); - } - } else { - setShowToast({ isError: false, isWarning: true, key: "warning", message: t("ERR_WS_ENTER_ATLEAST_ONE_FIELD") }); - } - } - - const selectedValuesData = (value, isDropDownValue = false, e) => { - let values = { ...fields }; - if (isDropDownValue) { - values[`${value}_data`] = e; - values[value] = e.title; - if (e.title == "PT_OTHERS" && value == "adhocPenaltyReason") values[`adhocPenaltyComment`] = ""; - if (e.title == "PT_OTHERS" && value == "adhocRebateReason") values[`adhocRebateComment`] = ""; - } else { - values[value] = e.target.value; - } - setFields(values); - } - - return ( - -
- {values && - -
- {values?.map((value, index) => { - return - })} -
-
-
- - -
-
} - { - wsAdditionalDetails?.additionalDetails?.isAdhocRebate ?
{ - showPopUp(true) - }} - > - {t("WS_PAYMENT_ADD_REBATE_PENALTY")} -
: null - } - {popup && - } - headerBarEnd={ - { - setFields(sessionFormData); - showPopUp(false); - }} />} - actionCancelLabel={t("PT_CANCEL")} - actionCancelOnSubmit={() => { - setFields(sessionFormData); - showPopUp(false); - }} - actionSaveLabel={t("PT_ADD")} - actionSaveOnSubmit={(e) => addAdhocRebatePenality(e)} - hideSubmit={false} - popupStyles={{ overflowY: "auto" }} - > - { -
- - {t("PT_AD_PENALTY")} - - {t("PT_TX_HEADS")} - -
- selectedValuesData("adhocPenaltyReason", true, e)} - selected={fields?.adhocPenaltyReason_data || ""} - isPropertyAssess={true} - name={"adhocPenaltyReason_data"} - t={t} - /> -
- {fields?.adhocPenaltyReason_data?.title === "PT_OTHERS" &&
- {t("PT_REASON")} -
- selectedValuesData("adhocPenaltyComment", false, e)} - {...(validation = { - isRequired: true, - pattern: "^[a-zA-Z-.`' ]*$", - type: "text", - title: t("TL_NAME_ERROR_MESSAGE"), - })} - /> -
-
} - {t("PT_HEAD_AMT")} -
- selectedValuesData("adhocPenalty", false, e)} - {...(validation = { - isRequired: true, - pattern: "^[1-9]+[0-9]*$", - title: t("ERR_DEFAULT_INPUT_FIELD_MSG"), - })} - /> - -
-
- - {t("PT_AD_REBATE")} - {t("PT_TX_HEADS")} -
- selectedValuesData("adhocRebateReason", true, e)} - selected={fields?.adhocRebateReason_data || ""} - name={"adhocRebateReason_data"} - isPropertyAssess={true} - t={t} - /> -
- {fields?.adhocRebateReason_data?.title === "PT_OTHERS" &&
- {t("PT_REASON")} - selectedValuesData("adhocRebateComment", false, e)} - {...(validation = { - isRequired: true, - pattern: "^[a-zA-Z-.`' ]*$", - type: "text", - title: t("TL_NAME_ERROR_MESSAGE"), - })} - /> -
} - {t("PT_HEAD_AMT")} -
- selectedValuesData("adhocRebate", false, e)} - {...(validation = { - isRequired: true, - pattern: "^[1-9]+[0-9]*$", - title: t("ERR_DEFAULT_INPUT_FIELD_MSG"), - })} - /> -
-
-
- }
} - {showToast && - } -
-
- ) -} - -export default WSFeeEstimation; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js deleted file mode 100644 index 75069dd741f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js +++ /dev/null @@ -1,30 +0,0 @@ -import React, { useCallback, useState } from "react"; -import { useTranslation } from "react-i18next"; - -const WeekDateRange = (props) => { - const [localSearchParams, setLocalSearchParams] = useState(() => ({})); - const { t } = useTranslation(); - const handleChange = useCallback((data) => { - setLocalSearchParams(() => ({ ...data })); - }, []); - - return ( -
-
-

{props.title}

-
- -
-
-
- ); -}; - -export default WeekDateRange; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js deleted file mode 100644 index e870f2e9a67..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js +++ /dev/null @@ -1,45 +0,0 @@ -import React from "react"; -import { Dropdown } from "@egovernments/digit-ui-react-components"; - -export const configAcceptDso = ({ t, dsoData, dso, selectVehicleNo, vehicleNoList, vehicleNo, vehicle, action }) => { - return { - label: { - heading: `ES_FSM_ACTION_TITLE_${action}`, - submit: `CS_COMMON_${action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("ES_FSM_ACTION_VEHICLE_REGISTRATION_NO"), - isMandatory: true, - type: "dropdown", - populators: ( - - ), - }, - { - label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), - isMandatory: true, - type: "text", - populators: { - name: "capacity", - validation: { - required: true, - }, - }, - disable: true, - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js deleted file mode 100644 index 418caf1e4bc..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js +++ /dev/null @@ -1,115 +0,0 @@ -import React from "react"; -import { DatePicker, Dropdown, CardLabelError } from "@egovernments/digit-ui-react-components"; - -function todayDate() { - var today = new Date(); - var dd = today.getDate(); - var mm = today.getMonth() + 1; - var yyyy = today.getFullYear(); - - if (dd < 10) { - dd = "0" + dd; - } - - if (mm < 10) { - mm = "0" + mm; - } - - return yyyy + "-" + mm + "-" + dd; -} - -function getFilteredDsoData(dsoData, vehicle) { - return dsoData?.filter((e) => e.vehicles?.find((veh) => veh?.type == vehicle?.code)); -} - -export const configAssignDso = ({ t, dsoData, dso, selectDSO, vehicleMenu, vehicle, selectVehicle, action }) => { - return { - label: { - heading: `ES_FSM_ACTION_TITLE_${action}`, - submit: `CS_COMMON_${action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("ES_FSM_ACTION_VEHICLE_TYPE"), - isMandatory: true, - type: "dropdown", - populators: ( - - ), - }, - { - label: t("ES_FSM_ACTION_DSO_NAME"), - isMandatory: true, - type: "dropdown", - populators: ( - - {getFilteredDsoData(dsoData, vehicle) && !getFilteredDsoData(dsoData, vehicle).length ? ( - {t("ES_COMMON_NO_DSO_AVAILABLE_WITH_SUCH_VEHICLE")} - ) : null} - - - ), - }, - { - label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), - isMandatory: true, - type: "text", - populators: { - name: "capacity", - validation: { - required: true, - }, - }, - disable: true, - }, - // { - // label: t("ES_FSM_ACTION_SERVICE_DATE"), - // isMandatory: true, - // type: "date", - // populators: { - // name: "date", - // validation: { - // required: true, - // }, - // min: Digit.Utils.date.getDate(), - // defaultValue: Digit.Utils.date.getDate(), - // }, - // }, - { - label: t("ES_FSM_ACTION_SERVICE_DATE"), - isMandatory: true, - type: "custom", - populators: { - name: "date", - validation: { - required: true, - }, - customProps: { min: Digit.Utils.date.getDate() }, - defaultValue: Digit.Utils.date.getDate(), - component: (props, customProps) => , - }, - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js deleted file mode 100644 index ca66865bb77..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js +++ /dev/null @@ -1,77 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configBPAApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, - error -}) => { - let isRejectOrRevocate = false; - if(action?.action == "REVOCATE" || action?.action == "REJECT" || action.action == "SKIP_PAYMENT" || action?.action == "SEND_BACK_TO_CITIZEN" || action?.action == "APPROVE") { - isRejectOrRevocate = true; - } - - let isCommentRequired = false; - if(action?.action == "REVOCATE" || action?.action == "REJECT") { - isCommentRequired = true; - } - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService}_${action?.action}`, - cancel: "BPA_CITIZEN_CANCEL_BUTTON", - }, - form: [ - { - body: [ - { - label: action.isTerminateState || isRejectOrRevocate ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), - type: "dropdown", - populators: action.isTerminateState || isRejectOrRevocate ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - isMandatory: isCommentRequired, - populators: { - name: "comments", - }, - }, - { - label: `${t("WF_APPROVAL_UPLOAD_HEAD")}`, - populators: ( - { - setUploadedFile(null); - }} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - accept= "image/*, .pdf, .png, .jpeg, .jpg" - iserror={error} - /> - ), - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js deleted file mode 100644 index 0bdba14bc5b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js +++ /dev/null @@ -1,71 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configBPAREGApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, - error -}) => { - let checkCondtions = true; - if (action?.action == "SENDBACKTOCITIZEN") checkCondtions = false; - if (action.isTerminateState) checkCondtions = false; - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, - cancel: "WF_EMPLOYEE_BPAREG_CANCEL", - }, - form: [ - { - body: [ - { - label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), - placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - type: "dropdown", - populators: !checkCondtions ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - { - label: t("BPA_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), - populators: ( - { - setUploadedFile(null); - }} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - accept= "image/*, .pdf, .png, .jpeg, .jpg" - iserror={error} - /> - ) - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js deleted file mode 100644 index a4c7c96b2fd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js +++ /dev/null @@ -1,46 +0,0 @@ -import React from "react"; -import { DatePicker } from "@egovernments/digit-ui-react-components"; - -export const configCompleteApplication = ({ t, vehicle, applicationCreatedTime = 0, action }) => ({ - label: { - heading: `ES_FSM_ACTION_TITLE_${action}`, - submit: `CS_COMMON_${action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("ES_FSM_ACTION_DESLUGED_DATE_LABEL"), - isMandatory: true, - type: "custom", - populators: { - name: "desluged", - validation: { - required: true, - }, - defaultValue: Digit.Utils.date.getDate(), - customProps: { - min: Digit.Utils.date.getDate(applicationCreatedTime), - max: Digit.Utils.date.getDate(), - }, - component: (props, customProps) => , - }, - }, - { - label: t("ES_FSM_ACTION_WASTE_VOLUME_LABEL"), - type: "text", - isMandatory: true, - populators: { - name: "wasteCollected", - validation: { - required: true, - validate: (value) => parseInt(value) <= parseInt(vehicle.capacity), - }, - error: `${t("ES_FSM_ACTION_INVALID_WASTE_VOLUME")} ${vehicle?.capacity} ${t("CS_COMMON_LITRES")}`, - }, - }, - ], - }, - ], -}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js deleted file mode 100644 index 12922b0575e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js +++ /dev/null @@ -1,79 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configNOCApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, - error -}) => { - - let isCommentRequired = false; - if(action?.action == "REVOCATE" || action?.action == "REJECT") { - isCommentRequired = true; - } - - let isRejectOrRevocate = false; - if(action?.action == "APPROVE" || action?.action == "REJECT" || action.action == "AUTO_APPROVE" || action.action == "AUTO_REJECT") { - isRejectOrRevocate = true; - } - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService}_${action?.action}`, - cancel: "CORE_LOGOUTPOPUP_CANCEL", - }, - form: [ - { - body: [ - { - label: action.isTerminateState || isRejectOrRevocate ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), - type: "dropdown", - populators: action.isTerminateState || isRejectOrRevocate ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - isMandatory: isCommentRequired, - populators: { - name: "comments", - }, - }, - { - label: `${t("WF_APPROVAL_UPLOAD_HEAD")}`, - populators: ( - { - setUploadedFile(null); - }} - showHint={true} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - accept= "image/*, .pdf, .png, .jpeg, .jpg" - iserror={error} - /> - ), - }, - ], - }, - ], - }; -}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js deleted file mode 100644 index afcc6a19be2..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js +++ /dev/null @@ -1,66 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configPTApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, -}) => { - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService}_${action?.action}`, - cancel: "ES_PT_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: action.isTerminateState || action?.action === "SENDBACKTOCITIZEN" ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), - // isMandatory: !action.isTerminateState, - type: "dropdown", - populators: action.isTerminateState || action?.action === "SENDBACKTOCITIZEN" ? null : ( - - ), - }, - { - label: t("ES_PT_ACTION_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - { - label: `${t("ES_PT_ATTACH_FILE")}${action.docUploadRequired ? " *" : ""}`, - populators: ( - { - setUploadedFile(null); - }} - showHint={true} - hintText={t("PT_ATTACH_RESTRICTIONS_SIZE")} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`ES_PT_ACTION_NO_FILEUPLOADED`)} - /> - ), - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js deleted file mode 100644 index dd04037aab6..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react"; -import { RadioButtons } from "@egovernments/digit-ui-react-components"; - -export const configPTAssessProperty = ({ t, action, financialYears, selectedFinancialYear, setSelectedFinancialYear }) => { - return { - label: { - heading: `WF_${action.action}_APPLICATION`, - submit: `WF_PT.CREATE_${action.action}`, - cancel: "ES_PT_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("ES_PT_FINANCIAL_YEARS"), - isMandatory: true, - type: "radio", - populators: ( - - ), - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js deleted file mode 100644 index 132a5bc6a7c..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js +++ /dev/null @@ -1,101 +0,0 @@ -import React from "react"; -import { Dropdown } from "@egovernments/digit-ui-react-components"; - -function getFilteredDsoData(dsoData, vehicle) { - return dsoData?.filter((e) => e.vehicles?.find((veh) => veh?.type == vehicle?.code)); -} - -export const configReassignDSO = ({ - t, - dsoData, - dso, - selectDSO, - vehicleMenu, - vehicle, - selectVehicle, - reassignReasonMenu, - reassignReason, - selectReassignReason, - action, - showReassignReason, -}) => ({ - label: { - heading: `ES_FSM_ACTION_TITLE_${action}`, - submit: `CS_COMMON_${action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - ...(showReassignReason - ? [ - { - label: t("ES_FSM_ACTION_REASSIGN_REASON"), - type: "dropdown", - isMandatory: true, - populators: ( - - ), - }, - ] - : []), - { - label: t("ES_FSM_ACTION_VEHICLE_TYPE"), - isMandatory: vehicle ? false : true, - type: "dropdown", - populators: ( - - ), - }, - { - label: t("ES_FSM_ACTION_DSO_NAME"), - isMandatory: true, - type: "dropdown", - populators: ( - - ), - }, - { - label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), - type: "text", - populators: { - name: "capacity", - validation: { - required: true, - }, - }, - disable: true, - }, - { - label: t("ES_FSM_ACTION_SERVICE_DATE"), - isMandatory: true, - type: "date", - populators: { - name: "date", - validation: { - required: true, - }, - min: Digit.Utils.date.getDate(), - defaultValue: Digit.Utils.date.getDate(), - }, - }, - ], - }, - ], -}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js deleted file mode 100644 index a18bdaf1110..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from "react"; -import { Dropdown } from "@egovernments/digit-ui-react-components"; - -export const configRejectApplication = ({ t, rejectMenu, setReason, reason, action }) => { - return { - label: { - heading: `ES_FSM_ACTION_TITLE_${action}`, - submit: `CS_COMMON_${action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t(`ES_FSM_ACTION_${action.toUpperCase()}_REASON`), - type: "dropdown", - populators: , - isMandatory: true, - }, - { - label: t("ES_FSM_ACTION_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js deleted file mode 100644 index 23b20e5be2b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js +++ /dev/null @@ -1,83 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configTLApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, -}) => { - let checkCondtions = true; - if (action?.action == "SENDBACKTOCITIZEN" || action?.action == "APPROVE") checkCondtions = false; - if (action.isTerminateState) checkCondtions = false; - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, - cancel: "WF_EMPLOYEE_NEWTL_CANCEL", - }, - form: [ - { - body: [ - { - label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), - placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - // isMandatory: false, - type: "dropdown", - populators: !checkCondtions ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - { - label: t("TL_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), - populators: ( - { - setUploadedFile(null); - }} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - /> - ) - }, - // { - // label: action.docUploadRequired ? t("ES_PT_UPLOAD_FILE") : null, - // populators: action.docUploadRequired ? ( - // { - // setUploadedFile(null); - // }} - // message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`ES_PT_ACTION_NO_FILEUPLOADED`)} - // /> - // ) : null, - // }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js deleted file mode 100644 index 2f5f2d45a6a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js +++ /dev/null @@ -1,73 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configWSApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, - error -}) => { - let checkCondtions = true; - if (action?.action?.includes("SEND_BACK") || action?.action == "APPROVE_FOR_CONNECTION") checkCondtions = false; - if (action.isTerminateState) checkCondtions = false; - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), - placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - // isMandatory: false, - type: "dropdown", - populators: !checkCondtions ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - { - label: t("WS_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), - populators: ( - { - setUploadedFile(null); - }} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - error={error} - iserror={error} - /> - ) - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js deleted file mode 100644 index 5acdcebe041..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js +++ /dev/null @@ -1,89 +0,0 @@ -import { Dropdown, UploadFile, DatePicker } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configWSDisConnectApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, - error -}) => { - let checkCondtions = true, isDatePickerDisplay = false; - if (action?.action?.includes("SEND_BACK") || action?.action == "APPROVE_FOR_DISCONNECTION" || action?.action == "RESUBMIT_APPLICATION") checkCondtions = false; - if (action.isTerminateState) checkCondtions = false; - if (action?.action == "EXECUTE_DISCONNECTION" || action?.action == "DISCONNECTION_EXECUTED") isDatePickerDisplay = true; - - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), - placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - // isMandatory: false, - type: "dropdown", - populators: !checkCondtions ? null : ( - - ), - }, - isDatePickerDisplay && { - label: t("ES_FSM_ACTION_SERVICE_DATE"), - isMandatory: isDatePickerDisplay ? true : false, - type: "custom", - populators: isDatePickerDisplay ? { - name: "date", - validation: { - required: true, - }, - // customProps: { max: Digit.Utils.date.getDate() }, - defaultValue: Digit.Utils.date.getDate(), - component: (props, customProps) => , - } : null, - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - { - label: t("WS_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), - populators: ( - { - setUploadedFile(null); - }} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - error={error} - iserror={error} - /> - ) - }, - ], - }, - ], - }; -}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js deleted file mode 100644 index 03beb885925..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js +++ /dev/null @@ -1,53 +0,0 @@ -import { Dropdown } from '@egovernments/digit-ui-react-components'; -import React, { useState } from 'react' - -const configApproveModal = ({ - t, - action -}) => { - if(action?.action === 'ADMINSANCTION'){ - return { - label: { - heading: `WORKS_APPROVE_ESTIMATE`, - submit: `WORKS_APPROVE_ESTIMATE`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } - - }else - return { - label: { - heading: `WORKS_APPROVE_LOI`, - submit: `WORKS_APPROVE_LOI`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } -} - -export default configApproveModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js deleted file mode 100644 index 06a29a26339..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js +++ /dev/null @@ -1,27 +0,0 @@ - -const configAttendanceApproveModal = ({ t, action }) => { - if (action?.applicationStatus === "APPROVED") { - return { - label: { - heading: t("ATM_PROCESSINGMODAL_HEADER"), - submit: t("ATM_FORWARD_FOR_APPROVAL"), - cancel: t("CS_COMMON_CANCEL"), - }, - form: [ - { - body: [ - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ], - }, - ] - }; - } -}; - -export default configAttendanceApproveModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js deleted file mode 100644 index 374219cc6d4..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js +++ /dev/null @@ -1,93 +0,0 @@ -const configAttendanceCheckModal = ({ - t, - action, - businessService, - approvers, - selectedApprover, - setSelectedApprover, - designation, - selectedDesignation, - setSelectedDesignation, - department, - selectedDept, - setSelectedDept, - approverLoading = false, -}) => { - let checkConditions = true; - if (action.isTerminateState) checkConditions = false; - - if (designation?.length === 0 || department?.length === 0) return {}; - - if (action?.applicationStatus === "ATTENDANCE_CHECKED") { - return { - label: { - heading: t("ATM_PROCESSINGMODAL_HEADER"), - submit: t("ATM_FORWARD_FOR_CHECK"), - cancel: t("WORKS_CANCEL"), - }, - form: [ - { - body: [ - { - isMandatory: true, - key: "department", - type: "radioordropdown", - label: !checkConditions ? null : t("ATM_APPROVER_DEPT"), - disable: false, - populators: { - name: "department", - optionsKey: "i18nKey", - error: "Department is required", - required: true, - options: department, - }, - }, - { - isMandatory: true, - key: "designation", - type: "radioordropdown", - label: !checkConditions ? null : t("ATM_APPROVER_DESIGNATION"), - disable: false, - populators: { - name: "designation", - optionsKey: "i18nKey", - error: "Designation is required", - required: true, - options: designation, - }, - }, - { - isMandatory: true, - key: "approvers", - type: "radioordropdown", - label: !checkConditions ? null : t("WORKS_APPROVER"), - disable: false, - populators: { - name: "approvers", - optionsKey: "nameOfEmp", - error: "Designation is required", - required: true, - options: approvers, - }, - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ], - }, - ], - defaultValues: { - department: "", - designation: "", - approvers: "", - comments: "", - }, - }; - } -}; - -export default configAttendanceCheckModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js deleted file mode 100644 index c732127aac7..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js +++ /dev/null @@ -1,61 +0,0 @@ -import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; -import React from 'react' - -const configAttendanceRejectModal = ({ - t, - empDepartment, - empDesignation, - empName -}) => { - - const fieldLabelStyle = { - "display" : "grid", - "gridTemplateColumns" : "60% 1fr" - }; - - return { - label: { - heading: t("ATM_PROCESSINGMODAL_HEADER"), - submit: t("ATM_CONFIRM_REJECT"), - cancel: t("CS_COMMON_CANCEL"), - }, - form: [ - { - body: [ - { - withoutLabel:true, - populators: - {t("ATM_DEPARTMENT")} - {empDepartment} - , - }, - { - withoutLabel:true, - populators: - {t("ATM_DESIGNATION")} - {empDesignation} - , - }, - { - withoutLabel:true, - populators: - {t("ATM_REJECTED_BY")} - {empName} - , - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - key: "org_name", - populators: { - name: "comments", - }, - }, - ] - } - ] - } - -} - -export default configAttendanceRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js deleted file mode 100644 index c267eb9f32f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js +++ /dev/null @@ -1,105 +0,0 @@ -import { Dropdown,Loader } from '@egovernments/digit-ui-react-components'; -import React,{useState} from 'react' - -const configCheckModal = ({ - t, - action, - businessService, - approvers, - selectedApprover, - setSelectedApprover, - designation, - selectedDesignation, - setSelectedDesignation, - department, - selectedDept, - setSelectedDept, - approverLoading=false, -}) => { - - let checkConditions = true - if (action.isTerminateState) checkConditions = false; - - if(designation?.length===0 || department?.length===0) return {} - - return { - label: { - heading: `WORKS_CHECK_FORWARD`, - submit: `WORKS_FORWARD_FOR_APPROVAL`, - cancel: "WORKS_CANCEL", - }, - form: [ - { - body:[ - { - label: !checkConditions ? null : t("WORKS_APPROVER_DEPT"), - placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - { - setSelectedDept(val) - setSelectedApprover("") - //setValue() - }} - selected={selectedDept} - t={t} - /> - ), - }, - { - label: !checkConditions ? null : t("WORKS_APPROVER_DESIGNATION"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - { - setSelectedDesignation(val) - setSelectedApprover("") - //resetting approver dropdown when dept/designation changes - }} - selected={selectedDesignation} - t={t} - /> - ), - }, - { - label: !checkConditions ? null : t("WORKS_APPROVER"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - approverLoading ? : - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } -} - -export default configCheckModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js deleted file mode 100644 index ae4be5af3fd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js +++ /dev/null @@ -1,127 +0,0 @@ -import { Dropdown,LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; -import React, { useState } from 'react' - -const configRejectModal = ({ - t, - action, - rejectReasons, - selectedReason, - setSelectedReason, - loiNumber, - department, - estimateNumber -}) => { - - let checkConditions = true - if (action.isTerminateState) checkConditions = false; - - if(rejectReasons?.length === 0) return {} - if(loiNumber){ - return { - label: { - heading: `WORKS_REJECT_LOI`, - submit: `WORKS_REJECT_LOI`, - //cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - withoutLabel:true, - populators: - {t("WORKS_DEPARTMENT")} - {"ENGG"} - , - }, - { - //label: t("WORKS_LOI_ID"), - //type: "text", - withoutLabel: true, - populators: - {t("WORKS_LOI_ID")} - {loiNumber} - - }, - { - label: !checkConditions ? null : t("WORKS_REJECT_REASON"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - // isMandatory: false, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } - }else{ - return { - label: { - heading: `WORKS_REJECT_ESTIMATE`, - submit: `WORKS_REJECT_ESTIMATE`, - //cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - withoutLabel:true, - populators: - {t("WORKS_DEPARTMENT")} - {"ENGG"} - , - }, - { - //label: t("WORKS_LOI_ID"), - //type: "text", - withoutLabel: true, - populators: - {t("WORKS_ESTIMATE_ID")} - {estimateNumber} - - }, - { - label: !checkConditions ? null : t("WORKS_REJECT_REASON"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - // isMandatory: false, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } - - } -} - -export default configRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js deleted file mode 100644 index cd01fdc4414..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react' -import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; - -const configViewBillApprovalModal = ({ - t, -}) => { - const fieldLabelStyle = { - "display" : "grid", - "gridTemplateColumns" : "60% 1fr" - }; - return { - label: { - heading: t("EXP_PROCESSINGMODAL_HEADER"), - submit: t("EXP_FORWARD_FOR_APPROVAL"), - cancel: t("CS_COMMON_CANCEL"), - }, - form: [ - { - body: [ - { - withoutLabel:true, - populators: - {t("EXP_DEPARTMENT")} - Engineering - , - }, - { - withoutLabel:true, - populators: - {t("EXP_DESIGNATION")} - Junior Engineer - , - }, - { - withoutLabel:true, - populators: - {t("EXP_APPROVER")} - {"RASHMI"} - , - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ], - }, - ], - defaultValues: { - comments: "", - }, - }; -} - -export default configViewBillApprovalModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js deleted file mode 100644 index 53204b28e75..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js +++ /dev/null @@ -1,107 +0,0 @@ -import { Dropdown, Loader } from '@egovernments/digit-ui-react-components'; -import React, { useState } from 'react' - -const configViewBillCheckModal = ({ - t, - approvers, - selectedApprover, - setSelectedApprover, - designation, - selectedDesignation, - setSelectedDesignation, - department, - selectedDept, - setSelectedDept, - approverLoading = false, -}) => { - - let checkConditions = true - - - if (designation?.length === 0 || department?.length === 0) return {} - - return { - label: { - heading: t("EXP_FORWARD_BILL_FOR_APPROVAL"), - submit: t("EXP_FORWARD_BILL_FOR_APPROVAL"), - cancel: t("CS_COMMON_CANCEL"), - }, - form: [ - { - body: [ - { - label: !checkConditions ? null : t("WORKS_APPROVER_DEPT"), - placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - { - setSelectedDept(val) - setSelectedApprover("") - //setValue() - }} - selected={selectedDept} - t={t} - /> - ), - }, - { - label: !checkConditions ? null : t("WORKS_APPROVER_DESIGNATION"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - name: "designation", - populators: !checkConditions ? null : ( - { - setSelectedDesignation(val) - setSelectedApprover("") - //resetting approver dropdown when dept/designation changes - }} - selected={selectedDesignation} - t={t} - /> - ), - }, - { - label: !checkConditions ? null : t("WORKS_APPROVER"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - approverLoading ? : - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } -} - -export default configViewBillCheckModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js deleted file mode 100644 index 716d6179d10..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react' -import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; - -const configViewBillRejectModal = ({ - t, -}) => { - - const fieldLabelStyle = { - "display" : "grid", - "gridTemplateColumns" : "60% 1fr" - }; - - return { - label: { - heading: t("EXP_PROCESSINGMODAL_HEADER"), - submit: t("EXP_CONFIRM_REJECT"), - cancel: t("CS_COMMON_CANCEL"), - }, - form: [ - { - body: [ - { - withoutLabel:true, - populators: - {t("EXP_DEPARTMENT")} - Engineering - , - }, - { - withoutLabel:true, - populators: - {t("EXP_DESIGNATION")} - Junior Engineer - , - }, - { - withoutLabel:true, - populators: - {t("EXP_REJECTED_BY")} - {"RASHMI"} - , - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ], - defaultValues : { - comments : "", - } - } -} - -export default configViewBillRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js deleted file mode 100644 index a736b8ed3eb..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js +++ /dev/null @@ -1,47 +0,0 @@ -import { configAssignDso } from "./AssignDso"; -import { configCompleteApplication } from "./CompleteApplication"; -import { configReassignDSO } from "./ReassignDso"; -import { configRejectApplication } from "./RejectApplication"; -import { configAcceptDso } from "./AcceptDso"; -import { configPTApproverApplication } from "./PTApproverApplication"; -import { configPTAssessProperty } from "./PTAssessProperty"; -import { configTLApproverApplication } from "./TLApproverApplication"; -import { configBPAREGApproverApplication } from "./BPAREGApproverApplication"; -import { configBPAApproverApplication } from "./BPAApproverApplication"; -import { configNOCApproverApplication } from "./NOCApproverApplication"; -import { configWSApproverApplication } from "./WSApproverApplication"; -import { configWSDisConnectApplication } from "./WSDisconnectApplication"; -import configCheckModal from "./configCheckModal" -import configApproveModal from "./configApproveModal" -import configRejectModal from "./configRejectModal" -import configAttendanceApproveModal from "./configAttendanceApproveModal"; -import configAttendanceCheckModal from "./configAttendanceCheckModal"; -import configAttendanceRejectModal from "./configAttendanceRejectModal"; -import configViewBillApproveModal from "./configViewBillApproveModal"; -import configViewBillCheckModal from "./configViewBillCheckModal"; -import configViewBillRejectModal from "./configViewBillRejectModal"; - -export { - configAttendanceRejectModal, - configAttendanceCheckModal, - configAttendanceApproveModal, - configCheckModal, - configApproveModal, - configRejectModal, - configAssignDso, - configCompleteApplication, - configReassignDSO, - configRejectApplication, - configAcceptDso, - configPTApproverApplication, - configPTAssessProperty, - configTLApproverApplication, - configBPAREGApproverApplication, - configBPAApproverApplication, - configNOCApproverApplication, - configWSApproverApplication, - configWSDisConnectApplication, - configViewBillRejectModal, - configViewBillCheckModal, - configViewBillApproveModal -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js deleted file mode 100644 index feb622ab712..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js +++ /dev/null @@ -1,368 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { useQueryClient } from "react-query"; -import { format } from "date-fns"; - -import { Loader } from "@egovernments/digit-ui-react-components"; - -import ActionModal from "./Modal"; - -import { useHistory, useParams } from "react-router-dom"; -import ApplicationDetailsContent from "./components/ApplicationDetailsContent"; -import ApplicationDetailsToast from "./components/ApplicationDetailsToast"; -import ApplicationDetailsActionBar from "./components/ApplicationDetailsActionBar"; -import ApplicationDetailsWarningPopup from "./components/ApplicationDetailsWarningPopup"; - -const ApplicationDetails = (props) => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - const state = Digit.ULBService.getStateId(); - const { t } = useTranslation(); - const history = useHistory(); - let { id: applicationNumber } = useParams(); - const [displayMenu, setDisplayMenu] = useState(false); - const [selectedAction, setSelectedAction] = useState(null); - const [showModal, setShowModal] = useState(false); - const [isEnableLoader, setIsEnableLoader] = useState(false); - const [isWarningPop, setWarningPopUp] = useState(false); - const [modify, setModify] = useState(false); - const [saveAttendanceState, setSaveAttendanceState] = useState({ displaySave : false, updatePayload: []}) - - const { - applicationDetails, - showToast, - setShowToast, - isLoading, - isDataLoading, - applicationData, - mutate, - nocMutation, - workflowDetails, - businessService, - closeToast, - moduleCode, - timelineStatusPrefix, - forcedActionPrefix, - statusAttribute, - ActionBarStyle, - MenuStyle, - paymentsList, - showTimeLine = true, - oldValue, - isInfoLabel = false, - clearDataDetails, - noBoxShadow, - sectionHeadStyle, - showActionBar = true - } = props; - - useEffect(() => { - if (showToast) { - workflowDetails.revalidate(); - } - }, [showToast]); - - function onActionSelect(action) { - if (action) { - if(action?.isToast){ - setShowToast({ key: "error", error: { message: action?.toastMessage } }); - setTimeout(closeToast, 5000); - } - else if (action?.isWarningPopUp) { - setWarningPopUp(true); - } else if (action?.redirectionUrll) { - //here do the loi edit upon rejection - if (action?.redirectionUrll?.action === "EDIT_LOI_APPLICATION") { - history.push(`${action?.redirectionUrll?.pathname}`, { data: action?.redirectionUrll?.state }); - } - if (action?.redirectionUrll?.action === "EDIT_ESTIMATE_APPLICATION") { - history.push(`${action?.redirectionUrll?.pathname}`,{ data: action?.redirectionUrll?.state }); - } - - } else if (!action?.redirectionUrl) { - if(action?.action === 'EDIT') setModify(true) - else setShowModal(true); - } else { - history.push({ - pathname: action.redirectionUrl?.pathname, - state: { ...action.redirectionUrl?.state }, - }); - } - } - setSelectedAction(action); - setDisplayMenu(false); - } - - const queryClient = useQueryClient(); - - const closeModal = () => { - setSelectedAction(null); - setShowModal(false); - }; - - const closeWarningPopup = () => { - setWarningPopUp(false); - }; - - const getResponseHeader = (action) => { - - if(action?.includes("CHECK")){ - return t("WORKS_LOI_RESPONSE_FORWARD_HEADER") - } else if (action?.includes("APPROVE")){ - return t("WORKS_LOI_RESPONSE_APPROVE_HEADER") - }else if(action?.includes("REJECT")){ - return t("WORKS_LOI_RESPONSE_REJECT_HEADER") - } - } - - const getResponseMessage = (action,updatedLOI) => { - - if (action?.includes("CHECK")) { - return t("WORKS_LOI_RESPONSE_MESSAGE_CHECK", { loiNumber: updatedLOI?.letterOfIndentNumber,name:"Nipun",designation:"SE" }) - } else if (action?.includes("APPROVE")) { - return t("WORKS_LOI_RESPONSE_MESSAGE_APPROVE", { loiNumber: updatedLOI?.letterOfIndentNumber }) - } else if (action?.includes("REJECT")) { - return t("WORKS_LOI_RESPONSE_MESSAGE_REJECT", { loiNumber: updatedLOI?.letterOfIndentNumber }) - } - } - - const getEstimateResponseHeader = (action) => { - - if(action?.includes("CHECK")){ - return t("WORKS_ESTIMATE_RESPONSE_FORWARD_HEADER") - } else if (action?.includes("TECHNICALSANCATION")){ - return t("WORKS_ESTIMATE_RESPONSE_FORWARD_HEADER") - }else if (action?.includes("ADMINSANCTION")){ - return t("WORKS_ESTIMATE_RESPONSE_APPROVE_HEADER") - }else if(action?.includes("REJECT")){ - return t("WORKS_ESTIMATE_RESPONSE_REJECT_HEADER") - } - } - - const getEstimateResponseMessage = (action,updatedEstimate) => { - - if (action?.includes("CHECK")) { - return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_CHECK", { estimateNumber: updatedEstimate?.estimateNumber,Name:"Super",Designation:"SE",Department:"Health" }) - } else if (action?.includes("TECHNICALSANCATION")) { - return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_CHECK", { estimateNumber: updatedEstimate?.estimateNumber,Name:"Super",Designation:"SE",Department:"Health" }) - } else if (action?.includes("ADMINSANCTION")) { - return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_APPROVE", { estimateNumber: updatedEstimate?.estimateNumber }) - } else if (action?.includes("REJECT")) { - return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_REJECT", { estimateNumber: updatedEstimate?.estimateNumber }) - } - } - - const getAttendanceResponseHeaderAndMessage = (action) => { - let response = {} - if (action?.includes("VERIFY")) { - response.header = t("ATM_ATTENDANCE_VERIFIED") - response.message = t("ATM_ATTENDANCE_VERIFIED_SUCCESS") - } else if (action?.includes("REJECT")) { - response.header = t("ATM_ATTENDANCE_REJECTED") - response.message = t("ATM_ATTENDANCE_REJECTED_SUCCESS") - } else if (action?.includes("APPROVE")) { - response.header = t("ATM_ATTENDANCE_APPROVED") - response.message = t("ATM_ATTENDANCE_APPROVED_SUCCESS") - } - return response - } - - const submitAction = async (data, nocData = false, isOBPS = {}) => { - const performedAction = data?.workflow?.action - setIsEnableLoader(true); - if (mutate) { - setIsEnableLoader(true); - mutate(data, { - onError: (error, variables) => { - setIsEnableLoader(false); - setShowToast({ key: "error", error }); - setTimeout(closeToast, 5000); - }, - onSuccess: (data, variables) => { - setIsEnableLoader(false); - //just history.push to the response component from here and show relevant details - if(data?.letterOfIndents?.[0]){ - const updatedLOI = data?.letterOfIndents?.[0] - const state = { - header:getResponseHeader(performedAction,updatedLOI), - id: updatedLOI?.letterOfIndentNumber, - info: t("WORKS_LOI_ID"), - message: getResponseMessage(performedAction,updatedLOI), - links: [ - { - name: t("WORKS_CREATE_NEW_LOI"), - redirectUrl: `/${window.contextPath}/employee/works/create-loi`, - code: "", - svg: "CreateEstimateIcon", - isVisible:false, - type:"add" - }, - { - name: t("WORKS_GOTO_LOI_INBOX"), - redirectUrl: `/${window.contextPath}/employee/works/LOIInbox`, - code: "", - svg: "CreateEstimateIcon", - isVisible:true, - type:"inbox" - }, - ], - responseData:data, - requestData:variables - } - history.push(`/${window.contextPath}/employee/works/response`, state) - } - if(data?.estimates?.[0]){ - const updatedEstimate = data?.estimates?.[0] - const state = { - header:getEstimateResponseHeader(performedAction,updatedEstimate), - id: updatedEstimate?.estimateNumber, - info: t("WORKS_ESTIMATE_ID"), - message: getEstimateResponseMessage(performedAction,updatedEstimate), - links: [ - { - name: t("WORKS_CREATE_ESTIMATE"), - redirectUrl: `/${window.contextPath}/employee/works/create-estimate`, - code: "", - svg: "CreateEstimateIcon", - isVisible:false, - type:"add" - }, - { - name: t("WORKS_GOTO_ESTIMATE_INBOX"), - redirectUrl: `/${window.contextPath}/employee/works/inbox`, - code: "", - svg: "RefreshIcon", - isVisible:true, - type:"inbox" - }, - ], - responseData:data, - requestData:variables - } - history.push(`/${window.contextPath}/employee/works/response`, state) - } - if (isOBPS?.bpa) { - data.selectedAction = selectedAction; - history.replace(`/${window?.contextPath}/employee/obps/response`, { data: data }); - } - if (isOBPS?.isStakeholder) { - data.selectedAction = selectedAction; - history.push(`/${window?.contextPath}/employee/obps/stakeholder-response`, { data: data }); - } - if (isOBPS?.isNoc) { - history.push(`/${window?.contextPath}/employee/noc/response`, { data: data }); - } - if (data?.Amendments?.length > 0 ){ - //RAIN-6981 instead just show a toast here with appropriate message - //show toast here and return - //history.push("/${window?.contextPath}/employee/ws/response-bill-amend", { status: true, state: data?.Amendments?.[0] }) - - if(variables?.AmendmentUpdate?.workflow?.action.includes("SEND_BACK")){ - setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_SEND_BACK_UPDATE_SUCCESS")}) - } else if (variables?.AmendmentUpdate?.workflow?.action.includes("RE-SUBMIT")){ - setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_RE_SUBMIT_UPDATE_SUCCESS") }) - } else if (variables?.AmendmentUpdate?.workflow?.action.includes("APPROVE")){ - setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_APPROVE_UPDATE_SUCCESS") }) - } - else if (variables?.AmendmentUpdate?.workflow?.action.includes("REJECT")){ - setShowToast({ key: "success", label: t("ES_MODIFYWSCONNECTION_REJECT_UPDATE_SUCCESS") }) - } - return - } - if(data?.musterRolls?.[0]) { - const musterRoll = data?.musterRolls?.[0] - const response = getAttendanceResponseHeaderAndMessage(performedAction) - const state = { - header: response?.header, - message: response?.message, - info: t("ATM_REGISTER_ID_WEEK"), - id: `${musterRoll.registerId} | ${format(new Date(musterRoll.startDate), "dd/MM/yyyy")} - ${format(new Date(musterRoll.endDate), "dd/MM/yyyy")}`, - } - history.push(`/${window.contextPath}/employee/attendencemgmt/response`, state) - } - setShowToast({ key: "success", action: selectedAction }); - clearDataDetails && setTimeout(clearDataDetails, 3000); - setTimeout(closeToast, 5000); - queryClient.clear(); - queryClient.refetchQueries("APPLICATION_SEARCH"); - //push false status when reject - - }, - }); - } - - closeModal(); - }; - - if (isLoading || isEnableLoader) { - return ; - } - - return ( - - {!isLoading ? ( - - - {showModal ? ( - - ) : null} - {isWarningPop ? ( - - ) : null} - - {showActionBar && } - - ) : ( - - )} - - ); -}; - -export default ApplicationDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh b/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh deleted file mode 100644 index 4909658c697..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -BASEDIR="$(cd "$(dirname "$0")" && pwd)" - -msg() { - echo -e "\n\n\033[32;32m$1\033[0m" -} - - -# msg "Pre-building all packages" -# yarn build -# sleep 5 - -msg "Building and publishing css" -cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag campaign-1.0 - - -# msg "Building and publishing libraries" -# cd "$BASEDIR/packages/modules/workbench-hcm" && rm -rf dist && yarn&& npm publish --tag workbench-1.0 - diff --git a/frontend/micro-ui/web/micro-ui-internals/publish.sh b/frontend/micro-ui/web/micro-ui-internals/publish.sh deleted file mode 100644 index 4909658c697..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/publish.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -BASEDIR="$(cd "$(dirname "$0")" && pwd)" - -msg() { - echo -e "\n\n\033[32;32m$1\033[0m" -} - - -# msg "Pre-building all packages" -# yarn build -# sleep 5 - -msg "Building and publishing css" -cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag campaign-1.0 - - -# msg "Building and publishing libraries" -# cd "$BASEDIR/packages/modules/workbench-hcm" && rm -rf dist && yarn&& npm publish --tag workbench-1.0 - diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh deleted file mode 100755 index 9de72331774..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -./scripts/run.sh core utilities diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh deleted file mode 100755 index 5b0c7b831ed..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -curl -v -X POST https://builds.digit.org/job/builds/job/digit-ui/buildWithParameters \ - --user saurabh-egov:114cbf3df675835931688b2d3f0014a1f7 \ - --data-urlencode json='{"parameter": [{"name":"BRANCH", "value":"origin/'$1'"}]}' - -# curl https://builds.digit.org/job/builds/job/digit-ui/lastBuild/api/json | grep --color result\":null - diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh deleted file mode 100755 index a1711fec55b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -./scripts/deploy.sh dev \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh deleted file mode 100755 index f00c59f13b8..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -MODULES=( "components" "core" "libraries" "example" ) - -RUNARGS=() -BUILDARGS=() - -for var in "$@" -do - BUILDARGS=( ${BUILDARGS[@]} build:"$var" ) - RUNARGS=( ${RUNARGS[@]} dev:"$var" ) -done - -a=0 -while [ "$a" -lt 3 ] -do - BUILD[$a]=build:${MODULES[$a]} - a=` expr $a + 1 ` -done - -echo "BUILDING MODULES:-" ${BUILD[*]} ${BUILDARGS[*]} -yarn run-p ${BUILD[*]} ${BUILDARGS[*]} - -b=0 -while [ "$b" -lt 4 ] -do - RUN[$b]=dev:${MODULES[$b]} - b=` expr $b + 1 ` -done - -echo "SERVING MODULES:-" ${RUN[*]} ${RUNARGS[*]} -yarn run-p ${RUN[*]} ${RUNARGS[*]} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/test.js b/frontend/micro-ui/web/micro-ui-internals/test.js deleted file mode 100644 index 60c958d0bac..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/test.js +++ /dev/null @@ -1,31 +0,0 @@ -const middleWare_1 = (data, _break, _next) => { - data.a = "a"; - _next(data); -}; - - -const middleWare_2 = (data, _break, _next) => { - data.b = "b"; - // _break(); - _next(data); -}; - -const middleWare_3 = (data, _break, _next) => { - data.c = "c"; - _next(data); -}; - -let middleWares = [middleWare_1, middleWare_2, middleWare_3]; - -const callMiddlewares = () => { - let applyBreak = false; - let itr = -1; - let _break = () => (applyBreak = true); - let _next = (data) => { - if (!applyBreak && ++itr < middleWares.length) middleWares[itr](data, _break, _next); - else return; - }; - _next({}); -}; - -callMiddlewares(); diff --git a/frontend/micro-ui/web/microplan/App.js b/frontend/micro-ui/web/microplan/App.js deleted file mode 100644 index afcd26669c6..00000000000 --- a/frontend/micro-ui/web/microplan/App.js +++ /dev/null @@ -1,61 +0,0 @@ -import React from "react"; -import { initLibraries } from "@egovernments/digit-ui-libraries"; - -import { DigitUI } from "@egovernments/digit-ui-module-core"; - -import { UICustomizations } from "./Customisations/UICustomizations"; -import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; - - -window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - -const enabledModules = [ - "DSS", - "NDSS", - "Utilities", - "HRMS", - "Engagement", - "Workbench", - "Microplanning" -]; - -const moduleReducers = (initData) => ({ - initData, -}); - -const initDigitUI = () => { - window.Digit.ComponentRegistryService.setupRegistry({ - - }); - - - initMicroplanningComponents() - window.Digit.Customizations = { - PGR: {}, - commonUiConfig: UICustomizations, - }; -}; - -initLibraries().then(() => { - initDigitUI(); -}); - -function App() { - window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - const stateCode = - window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || - process.env.REACT_APP_STATE_LEVEL_TENANT_ID; - if (!stateCode) { - return

stateCode is not defined

; - } - return ( - - ); -} - -export default App; diff --git a/frontend/micro-ui/web/microplan/Dockerfile b/frontend/micro-ui/web/microplan/Dockerfile deleted file mode 100644 index 56388b8e2d7..00000000000 --- a/frontend/micro-ui/web/microplan/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM egovio/alpine-node-builder-14:yarn AS build -#FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=4792" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \ - && node -e 'console.log("core only")' \ - && cd microplan/ \ - && chmod +x ./install-deps.sh \ - && ./install-deps.sh \ - && cd ../ \ - && yarn install \ - && yarn build:webpack - -FROM nginx:mainline-alpine -#FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/microplan-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/microplan/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/microplan/install-deps.sh b/frontend/micro-ui/web/microplan/install-deps.sh deleted file mode 100644 index b090c8d6f04..00000000000 --- a/frontend/micro-ui/web/microplan/install-deps.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -BRANCH="$(git branch --show-current)" - -echo "Main Branch: $BRANCH" - -INTERNALS="micro-ui-internals" -cd .. - -cp microplan/App.js src -cp microplan/package.json package.json -cp microplan/webpack.config.js webpack.config.js -cp microplan/inter-package.json $INTERNALS/package.json - -cp $INTERNALS/example/src/UICustomizations.js src/Customisations - -echo "UI :: microplan " && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" - diff --git a/frontend/micro-ui/web/microplan/inter-package.json b/frontend/micro-ui/web/microplan/inter-package.json deleted file mode 100644 index 635c9cc954b..00000000000 --- a/frontend/micro-ui/web/microplan/inter-package.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "name": "egovernments", - "version": "1.0.0", - "main": "index.js", - "workspaces": [ - "example", - "packages/css", - "packages/modules/*" - ], - "author": "JaganKumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "scripts": { - "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", - "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", - "start:dev": "run-p dev:**", - "start:script": "./scripts/create.sh", - "dev:css": "cd packages/css && yarn start", - "publish:css": "cd packages/css && yarn publish --access public", - "dev:example": "cd example && yarn start", - "dev:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn start", - "build": "run-p build:**", - "build:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn build", - "deploy:jenkins": "./scripts/jenkins.sh", - "clean": "rm -rf node_modules" - }, - "resolutions": { - "**/@babel/runtime": "7.20.1", - "**/babel-preset-react-app": "10.0.0", - "**/babel-loader": "8.2.2", - "**/@babel/core": "7.14.0", - "**/@babel/preset-env": "7.14.0", - "**/@babel/plugin-transform-modules-commonjs": "7.14.0", - "**/polished":"4.2.2", - "fast-uri":"2.1.0" - }, - "devDependencies": { - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "husky": {}, - "lint-staged": { - "*.{js,css,md}": "prettier --write" - }, - "dependencies": { - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "@egovernments/digit-ui-react-components": "1.8.1-beta.2", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0" - } -} diff --git a/frontend/micro-ui/web/microplan/nginx.conf b/frontend/micro-ui/web/microplan/nginx.conf deleted file mode 100644 index 9c84c01c4be..00000000000 --- a/frontend/micro-ui/web/microplan/nginx.conf +++ /dev/null @@ -1,12 +0,0 @@ -server -{ - listen 80; - underscores_in_headers on; - - location /microplan-ui - { - root /var/web; - index index.html index.htm; - try_files $uri $uri/ /microplan-ui/index.html; - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/microplan/package.json b/frontend/micro-ui/web/microplan/package.json deleted file mode 100644 index dff749d1780..00000000000 --- a/frontend/micro-ui/web/microplan/package.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "name": "micro-ui", - "version": "1.0.0", - "author": "Jagankumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "workspaces": [ - "micro-ui-internals/packages/modules/*" - ], - "homepage": "/microplan-ui", - "dependencies": { - "@egovernments/digit-ui-libraries": "1.8.2-beta.1", - "@egovernments/digit-ui-module-core": "1.8.2-beta.1", - "@egovernments/digit-ui-module-utilities": "1.0.1-beta.23", - "@egovernments/digit-ui-react-components": "1.8.2-beta.1", - "@egovernments/digit-ui-module-hcmmicroplanning":"0.0.1", - "@egovernments/digit-ui-components": "0.0.2-beta.2", - "babel-loader": "8.1.0", - "clean-webpack-plugin": "4.0.0", - "react": "17.0.2", - "react-dom": "17.0.2", - "jsonpath": "^1.1.1", - "react-router-dom": "5.3.0", - "react-scripts": "4.0.1", - "web-vitals": "1.1.2", - "terser-brunch": "^4.1.0", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "css-loader": "5.2.6", - "style-loader": "2.0.0", - "webpack-cli": "4.10.0" - }, - "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "7.21.0", - "file-loader": "^6.2.0", - "http-proxy-middleware": "1.3.1", - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "scripts": { - "start": "react-scripts start", - "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", - "build:prepare": "./build.sh", - "build:libraries": "cd micro-ui-internals && yarn build", - "build:prod": "webpack --mode production", - "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", - "clean": "rm -rf node_modules" - }, - "eslintConfig": { - "extends": [ - "react-app" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/microplan/webpack.config.js b/frontend/micro-ui/web/microplan/webpack.config.js deleted file mode 100644 index c8036364605..00000000000 --- a/frontend/micro-ui/web/microplan/webpack.config.js +++ /dev/null @@ -1,52 +0,0 @@ -const path = require("path"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); -// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; - -module.exports = { - // mode: 'development', - entry: "./src/index.js", - devtool: "none", - module: { - rules: [ - { - test: /\.(js)$/, - exclude: /node_modules/, - use: ["babel-loader"], - }, - { - test: /\.css$/i, - use: ["style-loader", "css-loader"], - }, - { - test: /\.(png|jpe?g|gif)$/i, - use: [ - { - loader: 'file-loader', - }, - ], - }, - ], - }, - output: { - filename: "[name].bundle.js", - path: path.resolve(__dirname, "build"), - publicPath: "/microplan-ui/", - }, - optimization: { - splitChunks: { - chunks: 'all', - minSize:20000, - maxSize:50000, - enforceSizeThreshold:50000, - minChunks:1, - maxAsyncRequests:30, - maxInitialRequests:30 - }, - }, - plugins: [ - new CleanWebpackPlugin(), - // new BundleAnalyzerPlugin(), - new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), - ], -}; \ No newline at end of file diff --git a/frontend/micro-ui/web/package.json b/frontend/micro-ui/web/package.json deleted file mode 100644 index e90ab5a52ba..00000000000 --- a/frontend/micro-ui/web/package.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "name": "micro-ui", - "version": "0.1.0", - "author": "Jagankumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "workspaces": [ - "micro-ui-internals/packages/libraries", - "micro-ui-internals/packages/react-components", - "micro-ui-internals/packages/modules/*" - ], - "homepage": "/digit-ui", - "dependencies": { - "@egovernments/digit-ui-libraries": "1.8.1-beta.4", - "@egovernments/digit-ui-module-workbench": "1.0.1-beta.16", - "@egovernments/digit-ui-module-core": "1.8.2-beta.2", - "@egovernments/digit-ui-module-hrms": "1.8.0-beta.2", - "@egovernments/digit-ui-react-components": "1.8.2-beta.6", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "@egovernments/digit-ui-module-dss": "1.8.0-beta", - "@egovernments/digit-ui-module-common": "1.8.0-beta", - "@egovernments/digit-ui-module-utilities": "1.0.0-beta", - "@egovernments/digit-ui-module-engagement": "1.5.20", - "babel-loader": "8.1.0", - "clean-webpack-plugin": "4.0.0", - "react": "17.0.2", - "react-dom": "17.0.2", - "jsonpath": "^1.1.1", - "react-router-dom": "5.3.0", - "react-scripts": "4.0.1", - "web-vitals": "1.1.2", - "terser-brunch": "^4.1.0", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "css-loader": "5.2.6", - "style-loader": "2.0.0", - "webpack-cli": "4.10.0" - }, - "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "7.21.0", - "http-proxy-middleware": "1.3.1", - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "scripts": { - "start": "react-scripts start", - "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", - "build:prepare": "./build.sh", - "build:libraries": "cd micro-ui-internals && yarn build", - "build:prod": "webpack --mode production", - "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", - "clean": "rm -rf node_modules" - }, - "eslintConfig": { - "extends": [ - "react-app" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/public/index.html b/frontend/micro-ui/web/public/index.html deleted file mode 100644 index 661b6fa2425..00000000000 --- a/frontend/micro-ui/web/public/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - DIGIT - - - - - - -
- - - - \ No newline at end of file diff --git a/frontend/micro-ui/web/public/robots.txt b/frontend/micro-ui/web/public/robots.txt deleted file mode 100644 index e9e57dc4d41..00000000000 --- a/frontend/micro-ui/web/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/frontend/micro-ui/web/src/App.js b/frontend/micro-ui/web/src/App.js deleted file mode 100644 index d871f8e8f4c..00000000000 --- a/frontend/micro-ui/web/src/App.js +++ /dev/null @@ -1,74 +0,0 @@ -import React from "react"; -import { initLibraries } from "@egovernments/digit-ui-libraries"; -import { - paymentConfigs, - PaymentLinks, - PaymentModule, -} from "@egovernments/digit-ui-module-common"; -import { DigitUI,initCoreComponents } from "@egovernments/digit-ui-module-core"; -import { initDSSComponents } from "@egovernments/digit-ui-module-dss"; -import { initEngagementComponents } from "@egovernments/digit-ui-module-engagement"; -import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms"; -import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; -import { UICustomizations } from "./Customisations/UICustomizations"; -import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; -// import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; - -window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - -const enabledModules = [ - "DSS", - "NDSS", - "Utilities", - "HRMS", - "Engagement", - "Workbench", - "Microplanning" -]; - -const moduleReducers = (initData) => ({ - initData, -}); - -const initDigitUI = () => { - window.Digit.ComponentRegistryService.setupRegistry({ - PaymentModule, - ...paymentConfigs, - PaymentLinks, - }); - initCoreComponents(); - initDSSComponents(); - initHRMSComponents(); - initEngagementComponents(); - initUtilitiesComponents(); - initWorkbenchComponents(); - - window.Digit.Customizations = { - PGR: {}, - commonUiConfig: UICustomizations, - }; -}; - -initLibraries().then(() => { - initDigitUI(); -}); - -function App() { - window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - const stateCode = - window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || - process.env.REACT_APP_STATE_LEVEL_TENANT_ID; - if (!stateCode) { - return

stateCode is not defined

; - } - return ( - - ); -} - -export default App; diff --git a/frontend/micro-ui/web/src/ComponentRegistry.js b/frontend/micro-ui/web/src/ComponentRegistry.js deleted file mode 100644 index 9bafce3dc89..00000000000 --- a/frontend/micro-ui/web/src/ComponentRegistry.js +++ /dev/null @@ -1,11 +0,0 @@ -class Registry { - constructor(registry = {}) { - this._registry = registry; - } - - getComponent(id) { - return this._registry[id]; - } -} - -export default Registry; diff --git a/frontend/micro-ui/web/src/Customisations/UICustomizations.js b/frontend/micro-ui/web/src/Customisations/UICustomizations.js deleted file mode 100644 index 6d17ab0d51b..00000000000 --- a/frontend/micro-ui/web/src/Customisations/UICustomizations.js +++ /dev/null @@ -1,428 +0,0 @@ -import { Link } from "react-router-dom"; -import _ from "lodash"; - -//create functions here based on module name set in mdms(eg->SearchProjectConfig) -//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] -// these functions will act as middlewares -var Digit = window.Digit || {}; - - - -const businessServiceMap = { - - "muster roll": "MR" -}; - -const inboxModuleNameMap = { - "muster-roll-approval": "muster-roll-service", -}; - -export const UICustomizations = { - businessServiceMap, - updatePayload: (applicationDetails, data, action, businessService) => { - - if (businessService === businessServiceMap.estimate) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - estimate: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap.contract) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - contract: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["muster roll"]) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - musterRoll: applicationDetails, - workflow, - }; - } - if(businessService === businessServiceMap?.["works.purchase"]){ - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - const additionalFieldsToSet = { - projectId:applicationDetails.additionalDetails.projectId, - invoiceDate:applicationDetails.billDate, - invoiceNumber:applicationDetails.referenceId.split('_')?.[1], - contractNumber:applicationDetails.referenceId.split('_')?.[0], - documents:applicationDetails.additionalDetails.documents - } - return { - bill: {...applicationDetails,...additionalFieldsToSet}, - workflow, - }; - } - }, - enableModalSubmit:(businessService,action,setModalSubmit,data)=>{ - if(businessService === businessServiceMap?.["muster roll"] && action.action==="APPROVE"){ - setModalSubmit(data?.acceptTerms) - } - }, - enableHrmsSearch: (businessService, action) => { - if (businessService === businessServiceMap.estimate) { - return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); - } - if (businessService === businessServiceMap.contract) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - if (businessService === businessServiceMap?.["muster roll"]) { - return action.action.includes("VERIFY"); - } - if(businessService === businessServiceMap?.["works.purchase"]){ - return action.action.includes("VERIFY_AND_FORWARD") - } - return false; - }, - getBusinessService: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return businessServiceMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return businessServiceMap?.contract; - } else if (moduleCode?.includes("muster roll")) { - return businessServiceMap?.["muster roll"]; - } - else if (moduleCode?.includes("works.purchase")) { - return businessServiceMap?.["works.purchase"]; - } - else if (moduleCode?.includes("works.wages")) { - return businessServiceMap?.["works.wages"]; - } - else if (moduleCode?.includes("works.supervision")) { - return businessServiceMap?.["works.supervision"]; - } - else { - return businessServiceMap; - } - }, - getInboxModuleName: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return inboxModuleNameMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return inboxModuleNameMap?.contracts; - } else if (moduleCode?.includes("attendence")) { - return inboxModuleNameMap?.attendencemgmt; - } else { - return inboxModuleNameMap; - } - }, - - AttendanceInboxConfig: { - preProcess: (data) => { - - //set tenantId - data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId(); - data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - - const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim(); - if(musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber - - const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim(); - if(attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName - - // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side) - const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee); - delete data.body.inbox.moduleSearchCriteria.assignee; - if (assignee?.code === "ASSIGNED_TO_ME") { - data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid; - } - - //cloning locality and workflow states to format them - // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []); - - let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null); - delete data.body.inbox.moduleSearchCriteria.orgId; - if(selectedOrg) { - data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber; - } - - // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null); - // delete data.body.inbox.moduleSearchCriteria.ward; - // if(selectedWard) { - // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code; - // } - - let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []); - let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []); - // delete data.body.inbox.moduleSearchCriteria.locality; - delete data.body.inbox.moduleSearchCriteria.state; - delete data.body.inbox.moduleSearchCriteria.ward; - - // locality = locality?.map((row) => row?.code); - states = Object.keys(states)?.filter((key) => states[key]); - ward = ward?.map((row) => row?.code); - - - // //adding formatted data to these keys - // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality; - if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states; - if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward; - const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {}); - if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code; - - //adding tenantId to moduleSearchCriteria - data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - - //setting limit and offset becoz somehow they are not getting set in muster inbox - data.body.inbox .limit = data.state.tableForm.limit - data.body.inbox.offset = data.state.tableForm.offset - delete data.state - return data; - }, - postProcess: (responseArray, uiConfig) => { - const statusOptions = responseArray?.statusMap - ?.filter((item) => item.applicationstatus) - ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` })); - if (uiConfig?.type === "filter") { - let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus"); - if (fieldConfig.length) { - fieldConfig[0].populators.options = statusOptions; - } - } - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "ATM_MUSTER_ROLL_ID") { - return ( - - - {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} - - - ); - } - if (key === "ATM_ATTENDANCE_WEEK") { - const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate( - value?.endDate, - "dd/MM/yyyy" - )}`; - return
{week}
; - } - if (key === "ATM_NO_OF_INDIVIDUALS") { - return
{value?.length}
; - } - if(key === "ATM_AMOUNT_IN_RS"){ - return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")}; - } - if (key === "ATM_SLA") { - return parseInt(value) > 0 ? ( - {t(value) || ""} - ) : ( - {t(value) || ""} - ); - } - if (key === "COMMON_WORKFLOW_STATES") { - return {t(`WF_MUSTOR_${value}`)} - } - //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default - return {t(`CASE_NOT_HANDLED`)} - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "ATM_MUSTER_ROLL_ID") - link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`; - }); - return link; - }, - populateReqCriteria: () => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - return { - url: "/org-services/organisation/v1/_search", - params: { limit: 50, offset: 0 }, - body: { - SearchCriteria: { - tenantId: tenantId, - functions : { - type : "CBO" - } - }, - }, - config: { - enabled: true, - select: (data) => { - return data?.organisations; - }, - }, - }; - }, - }, - SearchWageSeekerConfig: { - customValidationCheck: (data) => { - //checking both to and from date are present - const { createdFrom, createdTo } = data; - if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - - return false; - }, - preProcess: (data) => { - data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() }; - - let requestBody = { ...data.body.Individual }; - const pathConfig = { - name: "name.givenName", - }; - const dateConfig = { - createdFrom: "daystart", - createdTo: "dayend", - }; - const selectConfig = { - wardCode: "wardCode[0].code", - socialCategory: "socialCategory.code", - }; - const textConfig = ["name", "individualId"] - let Individual = Object.keys(requestBody) - .map((key) => { - if (selectConfig[key]) { - requestBody[key] = _.get(requestBody, selectConfig[key], null); - } else if (typeof requestBody[key] == "object") { - requestBody[key] = requestBody[key]?.code; - } else if (textConfig?.includes(key)) { - requestBody[key] = requestBody[key]?.trim() - } - return key; - }) - .filter((key) => requestBody[key]) - .reduce((acc, curr) => { - if (pathConfig[curr]) { - _.set(acc, pathConfig[curr], requestBody[curr]); - } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { - _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); - } else { - _.set(acc, curr, requestBody[curr]); - } - return acc; - }, {}); - - data.body.Individual = { ...Individual }; - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - //here we can add multiple conditions - //like if a cell is link then we return link - //first we can identify which column it belongs to then we can return relevant result - switch (key) { - case "MASTERS_WAGESEEKER_ID": - return ( - - - {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} - - - ); - - case "MASTERS_SOCIAL_CATEGORY": - return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); - - case "CORE_COMMON_PROFILE_CITY": - return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); - - case "MASTERS_WARD": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - - case "MASTERS_LOCALITY": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - default: - return t("ES_COMMON_NA"); - } - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "MASTERS_WAGESEEKER_ID") - link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; - }); - return link; - }, - additionalValidations: (type, data, keys) => { - if (type === "date") { - return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; - } - } - }, -}; diff --git a/frontend/micro-ui/web/src/Customisations/index.js b/frontend/micro-ui/web/src/Customisations/index.js deleted file mode 100644 index 803b1e8763e..00000000000 --- a/frontend/micro-ui/web/src/Customisations/index.js +++ /dev/null @@ -1,19 +0,0 @@ -import { ptComponents } from "./pt"; -import { tlComponents } from "./tl"; - -var Digit = window.Digit || {}; - -const customisedComponent = { - ...ptComponents, - ...tlComponents -} - - - -export const initCustomisationComponents = () => { - Object.entries(customisedComponent).forEach(([key, value]) => { - Digit.ComponentRegistryService.setComponent(key, value); - }); -}; - - diff --git a/frontend/micro-ui/web/src/Customisations/pt/index.js b/frontend/micro-ui/web/src/Customisations/pt/index.js deleted file mode 100644 index 0063fcd4774..00000000000 --- a/frontend/micro-ui/web/src/Customisations/pt/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import PropertyUsageType from "./pageComponents/PropertyUsageType"; -import PTVasikaDetails from "./pageComponents/PTVasikaDetails"; -import PTAllotmentDetails from "./pageComponents/PTAllotmentDetails"; -import PTBusinessDetails from "./pageComponents/PTBusinessDetails"; - - - -export const ptComponents = { - PropertyUsageType: PropertyUsageType, - PTVasikaDetail:PTVasikaDetails, - PTAllotmentDetails:PTAllotmentDetails, - PTBusinessDetails:PTBusinessDetails -}; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js deleted file mode 100644 index 569aa45e409..00000000000 --- a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js +++ /dev/null @@ -1,64 +0,0 @@ -import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; -import React, { useState } from "react"; -var validation ={}; -const PTAllotmentDetails = ({ t, config, onSelect, value, userType, formData }) => { - - const [ - val, setValue - ] = useState(formData?.[config.key]?.alotmentDetails||""); - - const goNext = () => { - onSelect(config.key, {alotmentDetails:val}); - }; - - - if (userType === "employee") { - return ( - - - {t("PT_VASIKA_NO_LABEL") } -
- setValue(e?.target?.value)} - // autoFocus={presentInModifyApplication} - /> -
-
-
- ); - } - return ( - - -
- {`${t("PT_VASIKA_ALLOTMENT_LABEL")}`} - setValue(e?.target?.value)} - - /> -
-
- {} -
- ); -}; - -export default PTAllotmentDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js deleted file mode 100644 index 3d28785e7e5..00000000000 --- a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js +++ /dev/null @@ -1,68 +0,0 @@ -import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; -import React, { useState } from "react"; -var validation ={}; -const PTBusinessDetails = ({ t, config, onSelect, value, userType, formData }) => { - - - const [ - val, setValue - ] = useState(formData?.[config.key]?.businessDetails||""); - - const goNext = () => { - onSelect(config.key, {businessDetails:val}); - }; - - - if (userType === "employee") { - return ( - - - {t("PT_VASIKA_NO_LABEL") } -
- setValue(e?.target?.value)} - // autoFocus={presentInModifyApplication} - /> -
-
- -
- ); - } - return ( - - - -
- {`${t("PT_VASIKA_BUS_DETAILS_LABEL")}`} - setValue(e?.target?.value)} - - /> -
- -
- {} -
- ); -}; - -export default PTBusinessDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js deleted file mode 100644 index 0e4b6895745..00000000000 --- a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js +++ /dev/null @@ -1,79 +0,0 @@ -import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; -import React, { useState } from "react"; -var validation ={}; -const PTVasikaDetails = ({ t, config, onSelect, value, userType, formData }) => { - - - const [ - val, setValue - ] = useState(formData?.[config.key]?.vasikaNo||""); - const [ - other, setOther - ] = useState(formData?.[config.key]?.vasikaArea||""); - const goNext = () => { - onSelect(config.key, {vasikaNo:val,vasikaArea:other}); - }; - - - if (userType === "employee") { - return ( - - - {t("PT_VASIKA_NO_LABEL") } -
- setValue(e?.target?.value)} - // autoFocus={presentInModifyApplication} - /> -
-
- -
- ); - } - return ( - - - -
- {`${t("PT_VASIKA_NO_LABEL")}`} - setValue(e?.target?.value)} - - /> -
- {`${t("PT_VASIKA_AREA_LABEL")}`} - setOther(e?.target?.value)} - /> -
- {} -
- ); -}; - -export default PTVasikaDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js deleted file mode 100644 index deade4fc2ad..00000000000 --- a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js +++ /dev/null @@ -1,134 +0,0 @@ -import { - CardLabel, CardLabelError, CitizenInfoLabel, Dropdown, FormStep, LabelFieldPair, RadioButtons -} from "@egovernments/digit-ui-react-components"; -import React, { useEffect, useState } from "react"; -import { useLocation } from "react-router-dom"; - -var Digit = window.Digit || {}; - -const PropertyUsageType = ({ t, config, onSelect, userType, formData, formState, setError, clearErrors, onBlur }) => { - const [usageCategoryMajor, setPropertyPurpose] = useState( - formData?.usageCategoryMajor && formData?.usageCategoryMajor?.code === "NONRESIDENTIAL.OTHERS" - ? { code: `${formData?.usageCategoryMajor?.code}`, i18nKey: `PROPERTYTAX_BILLING_SLAB_OTHERS` } - : formData?.usageCategoryMajor - ); - - const tenantId = Digit.ULBService.getCurrentTenantId(); - const stateId = tenantId.split(".")[0]; - const { data: Menu = { }, isLoading: menuLoading } = Digit.Hooks.pt.usePropertyMDMS(stateId, "PropertyTax", "UsageCategory") || { }; - let usagecat = []; - usagecat = Menu?.PropertyTax?.UsageCategory || []; - let i; - let menu = []; - - const { pathname } = useLocation(); - const presentInModifyApplication = pathname.includes("modify"); - - function usageCategoryMajorMenu(usagecat) { - if (userType === "employee") { - const catMenu = usagecat - ?.filter((e) => e?.code.split(".").length <= 2 && e.code !== "NONRESIDENTIAL") - ?.map((item) => { - const arr = item?.code.split("."); - if (arr.length == 2) return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + arr[1], code: item?.code }; - else return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + item?.code, code: item?.code }; - }); - return catMenu; - } else { - for (i = 0; i < 10; i++) { - if ( - Array.isArray(usagecat) && - usagecat.length > 0 && - usagecat[i].code.split(".")[0] == "NONRESIDENTIAL" && - usagecat[i].code.split(".").length == 2 - ) { - menu.push({ i18nKey: "PROPERTYTAX_BILLING_SLAB_" + usagecat[i].code.split(".")[1], code: usagecat[i].code }); - } - } - return menu; - } - } - - useEffect(() => { - if (!menuLoading && presentInModifyApplication && userType === "employee") { - const original = formData?.originalData?.usageCategory; - const selectedOption = usageCategoryMajorMenu(usagecat).filter((e) => e.code === original)[0]; - setPropertyPurpose(selectedOption); - } - }, [menuLoading]); - - const onSkip = () => onSelect(); - - - function selectPropertyPurpose(value) { - setPropertyPurpose(value); - } - - function goNext() { - if (usageCategoryMajor?.i18nKey === "PROPERTYTAX_BILLING_SLAB_OTHERS") { - usageCategoryMajor.i18nKey = "PROPERTYTAX_BILLING_SLAB_NONRESIDENTIAL"; - onSelect(config.key, usageCategoryMajor); - } else { - onSelect(config.key, usageCategoryMajor); - } - } - - useEffect(() => { - if (userType === "employee") { - if (!usageCategoryMajor) { - setError(config.key, { type: "required", message: t(`CORE_COMMON_REQUIRED_ERRMSG`) }); - } else { - clearErrors(config.key); - } - goNext(); - } - }, [usageCategoryMajor]); - - if (userType === "employee") { - return ( - - - {t("PT_ASSESMENT_INFO_USAGE_TYPE") + " *"} - { - selectPropertyPurpose(e); - }} - optionKey="i18nKey" - onBlur={onBlur} - t={t} - /> - - {formState.touched[config.key] ? ( - - {formState.errors?.[config.key]?.message} - - ) : null} - - ); - } - - return ( - - -
- -
-
- {} -
- ); -}; - -export default PropertyUsageType; diff --git a/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js b/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js deleted file mode 100644 index 642acc52090..00000000000 --- a/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js +++ /dev/null @@ -1,5 +0,0 @@ -export const TLCustomisations = { - customiseCreateFormData: (formData, licenceObject) => licenceObject, - customiseRenewalCreateFormData: (formData, licenceObject) => licenceObject, - customiseSendbackFormData: (formData, licenceObject) => licenceObject -} \ No newline at end of file diff --git a/frontend/micro-ui/web/src/Customisations/tl/index.js b/frontend/micro-ui/web/src/Customisations/tl/index.js deleted file mode 100644 index fe2ae4f4e6a..00000000000 --- a/frontend/micro-ui/web/src/Customisations/tl/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import TLUsageType from "./pageComponents/PropertyUsageType"; - - - -export const tlComponents = { - TLPropertyUsageType: TLUsageType, -}; diff --git a/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js b/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js deleted file mode 100644 index 5520a66fc5a..00000000000 --- a/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js +++ /dev/null @@ -1,136 +0,0 @@ -import { - CardLabel, CardLabelError, CitizenInfoLabel, Dropdown, FormStep, LabelFieldPair, RadioButtons -} from "@egovernments/digit-ui-react-components"; -import React, { useEffect, useState } from "react"; -import { useLocation } from "react-router-dom"; - -var Digit = window.Digit || {}; - -const TLUsageType = ({ t, config, onSelect, userType, formData, formState, setError, clearErrors, onBlur }) => { - const [usageCategoryMajor, setPropertyPurpose] = useState( - formData?.usageCategoryMajor && formData?.usageCategoryMajor?.code === "NONRESIDENTIAL.OTHERS" - ? { code: `${formData?.usageCategoryMajor?.code}`, i18nKey: `PROPERTYTAX_BILLING_SLAB_OTHERS` } - : formData?.usageCategoryMajor - ); - - const tenantId = Digit.ULBService.getCurrentTenantId(); - const stateId = tenantId.split(".")[0]; - const { data: Menu = { }, isLoading: menuLoading } = Digit.Hooks.pt.usePropertyMDMS(stateId, "PropertyTax", "UsageCategory") || { }; - let usagecat = []; - usagecat = Menu?.PropertyTax?.UsageCategory || []; - let i; - let menu = []; - - const { pathname } = useLocation(); - const presentInModifyApplication = pathname.includes("modify"); - - function usageCategoryMajorMenu(usagecat) { - if (userType === "employee") { - const catMenu = usagecat - ?.filter((e) => e?.code.split(".").length <= 2 && e.code !== "NONRESIDENTIAL") - ?.map((item) => { - const arr = item?.code.split("."); - if (arr.length == 2) return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + arr[1], code: item?.code }; - else return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + item?.code, code: item?.code }; - }); - return catMenu; - } else { - for (i = 0; i < 10; i++) { - if ( - Array.isArray(usagecat) && - usagecat.length > 0 && - usagecat[i].code.split(".")[0] == "NONRESIDENTIAL" && - usagecat[i].code.split(".").length == 2 - ) { - menu.push({ i18nKey: "PROPERTYTAX_BILLING_SLAB_" + usagecat[i].code.split(".")[1], code: usagecat[i].code }); - } - } - return menu; - } - } - - useEffect(() => { - if (!menuLoading && presentInModifyApplication && userType === "employee") { - const original = formData?.originalData?.usageCategory; - const selectedOption = usageCategoryMajorMenu(usagecat).filter((e) => e.code === original)[0]; - setPropertyPurpose(selectedOption); - } - }, [menuLoading]); - - const onSkip = () => onSelect(); - - - function selectPropertyPurpose(value) { - setPropertyPurpose(value); - } - - function goNext() { - if (usageCategoryMajor?.i18nKey === "PROPERTYTAX_BILLING_SLAB_OTHERS") { - usageCategoryMajor.i18nKey = "PROPERTYTAX_BILLING_SLAB_NONRESIDENTIAL"; - onSelect(config.key, usageCategoryMajor); - } else { - onSelect(config.key, usageCategoryMajor); - } - } - - useEffect(() => { - if (userType === "employee") { - if (!usageCategoryMajor) { - setError(config.key, { type: "required", message: t(`CORE_COMMON_REQUIRED_ERRMSG`) }); - } else { - clearErrors(config.key); - } - goNext(); - } - }, [usageCategoryMajor]); - - if (userType === "employee") { - return ( - - - {t("PT_ASSESMENT_INFO_USAGE_TYPE") + " *"} - { - selectPropertyPurpose(e); - }} - optionKey="i18nKey" - onBlur={onBlur} - t={t} - /> - - {formState.touched[config.key] ? ( - - {formState.errors?.[config.key]?.message} - - ) : null} - - ); - } - - return ( - - -
- - - -
-
- {} -
- ); -}; - -export default TLUsageType; diff --git a/frontend/micro-ui/web/src/index.css b/frontend/micro-ui/web/src/index.css deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frontend/micro-ui/web/src/index.js b/frontend/micro-ui/web/src/index.js deleted file mode 100644 index 9f20bf1b506..00000000000 --- a/frontend/micro-ui/web/src/index.js +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { initLibraries } from "@egovernments/digit-ui-libraries"; -import "./index.css"; -import App from './App'; -import { TLCustomisations } from './Customisations/tl/TLCustomisation'; - - -initLibraries(); - - -window.Digit.Customizations = { PGR: {} ,TL:TLCustomisations}; - -const user = window.Digit.SessionStorage.get("User"); - -if (!user || !user.access_token || !user.info) { - // login detection - - const parseValue = (value) => { - try { - return JSON.parse(value) - } catch (e) { - return value - } - } - - const getFromStorage = (key) => { - const value = window.localStorage.getItem(key); - return value && value !== "undefined" ? parseValue(value) : null; - } - - const token = getFromStorage("token") - - const citizenToken = getFromStorage("Citizen.token") - const citizenInfo = getFromStorage("Citizen.user-info") - const citizenTenantId = getFromStorage("Citizen.tenant-id") - - const employeeToken = getFromStorage("Employee.token") - const employeeInfo = getFromStorage("Employee.user-info") - const employeeTenantId = getFromStorage("Employee.tenant-id") - const userType = token === citizenToken ? "citizen" : "employee"; - - window.Digit.SessionStorage.set("user_type", userType); - window.Digit.SessionStorage.set("userType", userType); - - const getUserDetails = (access_token, info) => ({ token: access_token, access_token, info }) - - const userDetails = userType === "citizen" ? getUserDetails(citizenToken, citizenInfo) : getUserDetails(employeeToken, employeeInfo) - - window.Digit.SessionStorage.set("User", userDetails); - window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); - window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); - // end -} - -ReactDOM.render( - - - , - document.getElementById('root') -); - diff --git a/frontend/micro-ui/web/src/setupProxy.js b/frontend/micro-ui/web/src/setupProxy.js deleted file mode 100644 index 1b8eda94a19..00000000000 --- a/frontend/micro-ui/web/src/setupProxy.js +++ /dev/null @@ -1,30 +0,0 @@ -const { createProxyMiddleware } = require("http-proxy-middleware"); -const createProxy = createProxyMiddleware({ - target: process.env.REACT_APP_PROXY_URL, - changeOrigin: true, -}); -module.exports = function (app) { - [ - "/egov-mdms-service", - "/egov-location", - "/localization", - "/egov-workflow-v2", - "/pgr-services", - "/filestore", - "/egov-hrms", - "/user-otp", - "/user", - "/fsm", - "/billing-service", - "/collection-services", - "/pdf-service", - "/pg-service", - "/vehicle", - "/vendor", - "/property-services", - "/fsm-calculator/v1/billingSlab/_search", - "/muster-roll" - ].forEach((location) => - app.use(location, createProxy) - ); -}; diff --git a/frontend/micro-ui/web/webpack.config.js b/frontend/micro-ui/web/webpack.config.js deleted file mode 100644 index 5f3dc46967a..00000000000 --- a/frontend/micro-ui/web/webpack.config.js +++ /dev/null @@ -1,43 +0,0 @@ -const path = require("path"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); -// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; - -module.exports = { - // mode: 'development', - entry: "./src/index.js", - devtool: "none", - module: { - rules: [ - { - test: /\.(js)$/, - use: ["babel-loader"], - }, - { - test: /\.css$/i, - use: ["style-loader", "css-loader"], - } - ], - }, - output: { - filename: "[name].bundle.js", - path: path.resolve(__dirname, "build"), - publicPath: "/digit-ui/", - }, - optimization: { - splitChunks: { - chunks: 'all', - minSize:20000, - maxSize:50000, - enforceSizeThreshold:50000, - minChunks:1, - maxAsyncRequests:30, - maxInitialRequests:30 - }, - }, - plugins: [ - new CleanWebpackPlugin(), - // new BundleAnalyzerPlugin(), - new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), - ], -}; \ No newline at end of file diff --git a/frontend/micro-ui/web/workbench/App.js b/frontend/micro-ui/web/workbench/App.js deleted file mode 100644 index 93b15440c5e..00000000000 --- a/frontend/micro-ui/web/workbench/App.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * The above code initializes various Digit UI modules and components, sets up customizations, and - * renders the DigitUI component based on the enabled modules and state code. - * @returns The `App` component is being returned, which renders the `DigitUI` component with the - * specified props such as `stateCode`, `enabledModules`, `moduleReducers`, and `defaultLanding`. The - * `DigitUI` component is responsible for rendering the UI based on the provided configuration and - * modules. - */ -import React from "react"; -import { initLibraries } from "@egovernments/digit-ui-libraries"; -import { DigitUI } from "@egovernments/digit-ui-module-core"; -// import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms"; -import { UICustomizations } from "./Customisations/UICustomizations"; -import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; -import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; -import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; -import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager" - -window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - -const enabledModules = [ - "DSS", - "NDSS", - "Utilities", - // "HRMS", - "Engagement", - "Workbench", - "HCMWORKBENCH", - "Campaign" -]; - -const moduleReducers = (initData) => ({ - initData, -}); - -const initDigitUI = () => { - window.Digit.ComponentRegistryService.setupRegistry({}); - window.Digit.Customizations = { - PGR: {}, - commonUiConfig: UICustomizations, - }; - // initHRMSComponents(); - initUtilitiesComponents(); - initWorkbenchComponents(); - initWorkbenchHCMComponents(); - initCampaignComponents(); - -}; - -initLibraries().then(() => { - initDigitUI(); -}); - -function App() { - window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - const stateCode = - window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || - process.env.REACT_APP_STATE_LEVEL_TENANT_ID; - if (!stateCode) { - return

stateCode is not defined

; - } - return ( - - ); -} - -export default App; diff --git a/frontend/micro-ui/web/workbench/Dockerfile b/frontend/micro-ui/web/workbench/Dockerfile deleted file mode 100644 index 31b3912759b..00000000000 --- a/frontend/micro-ui/web/workbench/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM egovio/alpine-node-builder-14:yarn AS build -#FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=4792" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \ - && node -e 'console.log("core only")' \ - && cd workbench/ \ - && ./install-deps.sh \ - && cd ../ \ - && yarn install \ - && yarn build:webpack - -FROM nginx:mainline-alpine -#FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/workbench-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/workbench/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/workbench/install-deps.sh b/frontend/micro-ui/web/workbench/install-deps.sh deleted file mode 100755 index 54b8a4c3d7f..00000000000 --- a/frontend/micro-ui/web/workbench/install-deps.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -BRANCH="$(git branch --show-current)" - -echo "Main Branch: $BRANCH" - -INTERNALS="micro-ui-internals" -cd .. - -cp workbench/App.js src -cp workbench/package.json package.json -cp workbench/webpack.config.js webpack.config.js -cp workbench/inter-package.json $INTERNALS/package.json - -cp $INTERNALS/example/src/UICustomizations.js src/Customisations - -echo "UI :: workbench " && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" - diff --git a/frontend/micro-ui/web/workbench/inter-package.json b/frontend/micro-ui/web/workbench/inter-package.json deleted file mode 100644 index 5216443ec23..00000000000 --- a/frontend/micro-ui/web/workbench/inter-package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "egovernments", - "version": "1.0.0", - "main": "index.js", - "workspaces": [ - "example", - "packages/css", - "packages/modules/*" - ], - "author": "JaganKumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "scripts": { - "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", - "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", - "start:dev": "run-p dev:**", - "start:script": "./scripts/create.sh", - "dev:css": "cd packages/css && yarn start", - "publish:css": "cd packages/css && yarn publish --access public", - "dev:example": "cd example && yarn start", - "dev:campaign": "cd packages/modules/campaign-manager && yarn start", - "build": "run-p build:**", - "build:campaign": "cd packages/modules/campaign-manager && yarn build", - "deploy:jenkins": "./scripts/jenkins.sh", - "clean": "rm -rf node_modules" - }, - "resolutions": { - "**/@babel/runtime": "7.20.1", - "**/babel-preset-react-app": "10.0.0", - "**/ajv": "8.11.2", - "fast-uri":"2.1.0" - }, - "devDependencies": { - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "husky": {}, - "lint-staged": { - "*.{js,css,md}": "prettier --write" - }, - "dependencies": { - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "@egovernments/digit-ui-react-components": "1.8.2-beta.1", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0" - } -} diff --git a/frontend/micro-ui/web/workbench/nginx.conf b/frontend/micro-ui/web/workbench/nginx.conf deleted file mode 100644 index 974ef82f241..00000000000 --- a/frontend/micro-ui/web/workbench/nginx.conf +++ /dev/null @@ -1,12 +0,0 @@ -server -{ - listen 80; - underscores_in_headers on; - - location /workbench-ui - { - root /var/web; - index index.html index.htm; - try_files $uri $uri/ /workbench-ui/index.html; - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/workbench/package.json b/frontend/micro-ui/web/workbench/package.json deleted file mode 100644 index 7cc60ef7bff..00000000000 --- a/frontend/micro-ui/web/workbench/package.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "name": "micro-ui", - "version": "1.0.0", - "author": "Jagankumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "workspaces": [ - "micro-ui-internals/packages/modules/*" - ], - "homepage": "/workbench-ui", - "dependencies": { - "@egovernments/digit-ui-libraries": "1.8.2-beta.1", - "@egovernments/digit-ui-module-workbench": "1.0.2-beta.3", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "@egovernments/digit-ui-module-core": "1.8.2-beta.2", - "@egovernments/digit-ui-module-utilities": "1.0.1-beta.30", - "@egovernments/digit-ui-react-components": "1.8.2-beta.6", - "@egovernments/digit-ui-module-hcmworkbench":"0.0.38", - "@egovernments/digit-ui-module-campaign-manager": "0.0.1", - "babel-loader": "8.1.0", - "clean-webpack-plugin": "4.0.0", - "react": "17.0.2", - "react-dom": "17.0.2", - "jsonpath": "^1.1.1", - "react-router-dom": "5.3.0", - "react-scripts": "4.0.1", - "web-vitals": "1.1.2", - "terser-brunch": "^4.1.0", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "css-loader": "5.2.6", - "style-loader": "2.0.0", - "webpack-cli": "4.10.0" - }, - "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "7.21.0", - "http-proxy-middleware": "1.3.1", - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "resolutions": { - "**/babel-loader": "8.2.2", - "**/@babel/core": "7.14.0", - "**/@babel/preset-env": "7.14.0", - "**/@babel/plugin-transform-modules-commonjs": "7.14.0", - "**/polished":"4.2.2", - "fast-uri":"2.1.0" - }, - "scripts": { - "start": "react-scripts start", - "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", - "build:prepare": "./build.sh", - "build:libraries": "cd micro-ui-internals && yarn build", - "build:prod": "webpack --mode production", - "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", - "clean": "rm -rf node_modules" - }, - "eslintConfig": { - "extends": [ - "react-app" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/frontend/micro-ui/web/workbench/webpack.config.js b/frontend/micro-ui/web/workbench/webpack.config.js deleted file mode 100644 index c19e631fe01..00000000000 --- a/frontend/micro-ui/web/workbench/webpack.config.js +++ /dev/null @@ -1,44 +0,0 @@ -const path = require("path"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); -// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; - -module.exports = { - // mode: 'development', - entry: "./src/index.js", - devtool: "none", - module: { - rules: [ - { - test: /\.(js)$/, - exclude: /node_modules/, - use: ["babel-loader"], - }, - { - test: /\.css$/i, - use: ["style-loader", "css-loader"], - } - ], - }, - output: { - filename: "[name].bundle.js", - path: path.resolve(__dirname, "build"), - publicPath: "/workbench-ui/", - }, - optimization: { - splitChunks: { - chunks: 'all', - minSize:20000, - maxSize:50000, - enforceSizeThreshold:50000, - minChunks:1, - maxAsyncRequests:30, - maxInitialRequests:30 - }, - }, - plugins: [ - new CleanWebpackPlugin(), - // new BundleAnalyzerPlugin(), - new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), - ], -}; \ No newline at end of file diff --git a/health-services/project-factory/CHANGELOG.md b/health-services/project-factory/CHANGELOG.md index 55f990d91ba..8781f319963 100644 --- a/health-services/project-factory/CHANGELOG.md +++ b/health-services/project-factory/CHANGELOG.md @@ -8,3 +8,9 @@ All notable changes to this module will be documented in this file. 3. Create Data: Validates and creates resource details of type facility,user and boundary. 4. Generate Data: Generates sheet data of type facility,user and boundary. 5. Boundary and Resource Validation: Validates boundaries and resources during campaign creation and updating. + +## 0.2.0 - 2024-08-7 +#### ProjectFactory service version 0.2 + 1. Timeline integration for workflow of campaign. + 2. Call user, facility and boundary generate when boundaries changed in campaign update flow + 3. Generate target template based on delivery conditions changed to anything from default. diff --git a/health-services/project-factory/README.md b/health-services/project-factory/README.md index 40aee6d33bc..0b545626fe6 100644 --- a/health-services/project-factory/README.md +++ b/health-services/project-factory/README.md @@ -1,84 +1,93 @@ -# ProjectFactory-Service +# ProjectFactory Service -The Project Factory Service is responsible for managing project-type campaigns, including creating, updating, searching, and creating campaigns. +The **ProjectFactory Service** is responsible for managing project-type campaigns, including creating, updating, searching, and generating campaign data. -### DB UML Diagram +## DB UML Diagram -![image](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/8c43998d-742b-4629-ae90-63ab2b18772b) -![image](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/3ff9609d-771a-4c6e-a769-54766e7111f7) +![DB UML Diagram](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/8c43998d-742b-4629-ae90-63ab2b18772b) +![DB UML Diagram](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/3ff9609d-771a-4c6e-a769-54766e7111f7) +## Service Dependencies -### Service Dependencies +### Core Services -#### Core services +- `egov-localization` +- `egov-filestore` +- `egov-persister` +- `egov-mdms` +- `egov-idgen` +- `egov-boundaryservice-v2` -- egov-localization -- egov-filestore -- egov-persister -- egov-mdms -- egov-idgen -- egov-boundaryservice-v2 +### Health Services -#### Health services -- health-project -- health-hrms -- health-facility +- `health-project` +- `health-hrms` +- `health-facility` -### Swagger API Contract -Please refer to the below Swagger API contract, for ProjectFactory service to understand the structure of APIs and to have visualization of all internal APIs [Swagger API contract](https://editor.swagger.io/?url=https://raw.githubusercontent.com/jagankumar-egov/DIGIT-Specs/hcm-workbench/Domain%20Services/Health/project-factory.yaml) +### Caching +- `Redis` is now used to store cache for frequently accessed data to improve performance. + +## Swagger API Contract + +For the structure and visualization of APIs, refer to the [Swagger API contract](https://editor.swagger.io/?url=https://raw.githubusercontent.com/jagankumar-egov/DIGIT-Specs/hcm-workbench/Domain%20Services/Health/project-factory.yaml). ## Service Details -### Funcatinality -1. ProjectFactory Service manages campaigns: creation, updating, searching, and data generation. -2. Project Mapping : In campaign creation full project mapping is done with staff, facility and resources along with proper target values. -3. Create Data: Validates and creates resource details of type facility,user and boundary. -4. Generate Data: Generates sheet data of type facility,user and boundary. -5. Boundary and Resource Validation: Validates boundaries and resources during campaign creation and updating. - -### Feature -1. Functionality to create campaigns easily. -2. Uploading generated datas sheets to filestore and return filestore id for easy access. -3. Supports localisation. -4. Customizable Delivery Rules: Allows defining delivery rules for projects based on specific criteria. -5. Search and Filtering: Enables searching and filtering campaigns based on various parameters like status, date, and creator. -6. Batch Processing: Supports batch processing for creating and updating multiple campaigns simultaneously. +### Functionality + +1. **Campaign Management**: Manages project-type campaigns, including creation, updating, searching, and data generation. +2. **Project Mapping**: Completes full project mapping with staff, facility, and resources along with proper target values during campaign creation. +3. **Data Creation**: Validates and creates resource details of types `facility`, `user`, and `boundary`. +4. **Data Generation**: Generates sheet data of types `facility`, `user`, and `boundary`. +5. **Validation**: Validates boundaries and resources during campaign creation and updating. + +### Features + +1. **Easy Campaign Creation**: Facilitates easy creation of campaigns. +2. **File Storage**: Uploads generated data sheets to `egov-filestore` and returns the file store ID for easy access. +3. **Localization Support**: Supports localization for multi-language adaptability. +4. **Customizable Delivery Rules**: Allows defining delivery rules for projects based on specific criteria. +5. **Search and Filtering**: Enables searching and filtering campaigns based on parameters like status, date, and creator. +6. **Batch Processing**: Supports batch processing for creating and updating multiple campaigns simultaneously. +7. **Caching with Redis**: Improves performance by caching frequently accessed data. ### External Libraries Used -[xlsx](https://github.com/SheetJS/sheetjs):- For reading and writing Excel files. -[ajv](https://github.com/ajv-validator/ajv):- For JSON schema validation. +- **[xlsx](https://github.com/SheetJS/sheetjs)**: For reading and writing Excel files. +- **[ajv](https://github.com/ajv-validator/ajv)**: For JSON schema validation. +- **[lodash](https://github.com/lodash/lodash)**: For utility functions like data manipulation and object iteration. -[lodash](https://github.com/lodash/lodash):- For utility functions like data manipulation and object iteration. +## Configuration +- **Persister Config**: [Link](https://github.com/egovernments/configs/blob/UNIFIED-UAT/health/egov-persister/project-factory-persister.yml) +- **Helm Chart Details**: [Link](https://github.com/egovernments/DIGIT-DevOps/blob/unified-env/deploy-as-code/helm/charts/health-services/project-factory/values.yaml) -### Configuration +## API Endpoints -- Persister config: [here](https://github.com/egovernments/configs/blob/UNIFIED-UAT/health/egov-persister/project-factory-persister.yml) -- Helm chart details: [here](https://github.com/egovernments/DIGIT-DevOps/blob/unified-env/deploy-as-code/helm/charts/health-services/project-factory/values.yaml) - -### API Endpoints +- **`POST /project-factory/v1/project-type/create`**: Creates a new project-type campaign. +- **`PUT /project-factory/v1/project-type/update`**: Updates an existing project-type campaign. +- **`POST /project-factory/v1/project-type/search`**: Searches for project-type campaigns based on specified criteria. +- **`POST /project-factory/v1/data/_create`**: Creates or validates resource data (e.g., facility, user, boundary). +- **`POST /project-factory/v1/data/_search`**: Searches for resource data based on specified criteria. +- **`POST /project-factory/v1/data/_generate`**: Initiates the generation of new data based on provided parameters. +- **`GET /project-factory/v1/data/_download`**: Downloads resource data based on specified criteria. -- `/project-factory/v1/project-type/create`: Creates a new project type campaign. -- `/project-factory/v1/project-type/update`: Updates an existing project type campaign. -- `/project-factory/v1/project-type/search`: Searches for project type campaigns based on specified criteria. -- `/project-factory/v1/data/_create`: Creates or validates resource data (e.g., facility, user, boundary). -- `/project-factory/v1/data/_search`: Searches for resource data based on specified criteria. -- `/project-factory/v1/data/_generate`: Initiates the generation of new data based on provided parameters. -- `/project-factory/v1/data/_download`: Downloads resource data based on specified criteria. +## Kafka Consumers +- **`start-campaign-mapping`**: Initiates the mapping process for campaigns. -### Kafka Consumers +## Kafka Producers -- start-campaign-mapping: This topic is used by the service to initiate the mapping process for campaigns. +- **`save-project-campaign-details`**: Saves project campaign details after creation. +- **`update-project-campaign-details`**: Updates project campaign details. +- **`create-resource-details`**: Creates resource details. +- **`update-resource-details`**: Updates resource details. +- **`create-resource-activity`**: Creates resource activity. +- **`create-generated-resource-details`**: Saves details for generated resources. +- **`update-generated-resource-details`**: Updates details for generated resources. -### Kafka Producers +## Redis Caching -- save-project-campaign-details: This topic is used to save project campaign details after creation. -- update-project-campaign-details: This topic is used to update project campaign details. -- create-resource-details: This topic is used to create resource details. -- update-resource-details: This topic is used to update resource details. -- create-resource-activity: This topic is used to create resource activity creation. -- create-generated-resource-details: This topic is used to save details for generated resources. -- update-generated-resource-details: This topic is used to update details for generated resources. +- **Purpose**: Enhances performance by caching frequently accessed data and reducing the load on the database. +- **Usage**: Commonly used to store temporary data like search results, and other frequently accessed resources. diff --git a/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql b/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql new file mode 100644 index 00000000000..dfd13713c78 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql @@ -0,0 +1,13 @@ +DO $$ +DECLARE + table_name1 TEXT := 'eg_cm_generated_resource_details'; + column_name1 TEXT := 'campaignId'; +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = table_name1 + AND column_name = column_name1 + ) THEN + EXECUTE format('ALTER TABLE %I ADD COLUMN %I character varying(128);', table_name1, column_name1); + END IF; +END $$; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql b/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql new file mode 100644 index 00000000000..e7b4037bd8d --- /dev/null +++ b/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql @@ -0,0 +1,11 @@ +CREATE TABLE health.eg_cm_campaign_process ( + id VARCHAR(128) PRIMARY KEY, + campaignId VARCHAR(128) NOT NULL, + type VARCHAR(128), + status VARCHAR(128), + details JSONB, + createdtime BIGINT, + lastmodifiedtime BIGINT, + additionaldetails JSONB, + CONSTRAINT fk_campaignId FOREIGN KEY (campaignId) REFERENCES health.eg_cm_campaign_details(id) +); diff --git a/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql b/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql new file mode 100644 index 00000000000..a67a8061f42 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql @@ -0,0 +1,24 @@ +DO $$ +DECLARE + table_name1 TEXT := 'eg_cm_generated_resource_details'; + column_name1 TEXT := 'campaignId'; + column_name2 TEXT := 'campaignid'; +BEGIN + -- Check if "campaignId" column exists and drop it if it does + IF EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = table_name1 + AND column_name = column_name1 + ) THEN + EXECUTE format('ALTER TABLE %I DROP COLUMN %I;', table_name1, column_name1); + END IF; + + -- Check if "campaignid" column exists (case-insensitive) and create it if it doesn't + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = table_name1 + AND lower(column_name) = lower(column_name2) + ) THEN + EXECUTE format('ALTER TABLE %I ADD COLUMN %I character varying(128);', table_name1, column_name2); + END IF; +END $$; diff --git a/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql b/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql new file mode 100644 index 00000000000..9142fc152e0 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql @@ -0,0 +1,3 @@ +-- Migration script to remove the foreign key constraint +ALTER TABLE eg_cm_campaign_process DROP CONSTRAINT IF EXISTS fk_campaignId; +ALTER TABLE eg_cm_resource_activity DROP CONSTRAINT IF EXISTS eg_cm_resource_activity_resourceDetailsId_fkey; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql b/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql new file mode 100644 index 00000000000..d9bfbd0af53 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql @@ -0,0 +1,10 @@ +-- Step 1: Remove duplicate rows +DELETE FROM eg_cm_campaign_process a +USING health.eg_cm_campaign_process b +WHERE a.id < b.id +AND a.campaignId = b.campaignId +AND a.type = b.type; + +-- Step 2: Add the unique constraint +ALTER TABLE eg_cm_campaign_process +ADD CONSTRAINT uq_campaignId_type UNIQUE (campaignId, type); diff --git a/health-services/project-factory/migration/migrate.sh b/health-services/project-factory/migration/migrate.sh index 5593a173eba..c433c239956 100755 --- a/health-services/project-factory/migration/migrate.sh +++ b/health-services/project-factory/migration/migrate.sh @@ -1,3 +1,4 @@ #!/bin/sh +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS repair flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true migrate \ No newline at end of file diff --git a/health-services/project-factory/package-lock.json b/health-services/project-factory/package-lock.json index 5d9d7df918a..a7479aa962a 100644 --- a/health-services/project-factory/package-lock.json +++ b/health-services/project-factory/package-lock.json @@ -18,6 +18,7 @@ "hash-sum": "2.0.0", "helmet": "7.1.0", "http-proxy-middleware": "^3.0.0", + "ioredis": "^5.4.1", "jaeger-client": "^3.19.0", "jsonpath": "1.1.1", "kafka-node": "5.0.0", @@ -40,6 +41,7 @@ "@types/http-proxy-middleware": "^1.0.0", "@types/jaeger-client": "^3.18.7", "@types/jest": "29.5.12", + "@types/lodash": "^4.17.5", "@types/morgan": "1.9.9", "@types/node": "20.11.29", "@types/pg": "8.11.3", @@ -53,22 +55,11 @@ "typescript": "5.4.2" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -78,38 +69,43 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.4", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", + "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.4", + "@babel/generator": "^7.24.5", "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.4", - "@babel/parser": "^7.24.4", + "@babel/helper-module-transforms": "^7.24.5", + "@babel/helpers": "^7.24.5", + "@babel/parser": "^7.24.5", "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -124,26 +120,11 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/core/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -160,25 +141,24 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.24.4", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", + "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.24.0", + "@babel/types": "^7.24.5", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -192,7 +172,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-validator-option": "^7.23.5", @@ -204,22 +183,35 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -229,7 +221,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -243,7 +234,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -256,7 +246,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.24.0" }, @@ -265,17 +254,16 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", + "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-simple-access": "^7.24.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -285,36 +273,33 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", - "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz", + "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", + "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", + "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -325,17 +310,15 @@ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -345,32 +328,31 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.4", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", + "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0" + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -384,7 +366,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -397,7 +378,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -412,7 +392,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -421,25 +400,13 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } + "dev": true }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -449,7 +416,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -458,9 +424,10 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.4", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", "dev": true, - "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -473,7 +440,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -486,7 +452,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -499,7 +464,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -512,7 +476,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -525,7 +488,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -538,7 +500,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -554,7 +515,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -567,7 +527,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -580,7 +539,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -593,7 +551,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -606,7 +563,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -619,7 +575,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -632,7 +587,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -648,7 +602,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -664,7 +617,6 @@ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/parser": "^7.24.0", @@ -674,35 +626,20 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/template/node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/traverse": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", - "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", + "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.1", - "@babel/generator": "^7.24.1", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/types": "^7.24.5", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -710,26 +647,11 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/traverse/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -747,7 +669,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -756,18 +677,16 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -778,14 +697,12 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@colors/colors": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "license": "MIT", "engines": { "node": ">=0.1.90" } @@ -795,7 +712,6 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -808,7 +724,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -818,7 +733,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "license": "MIT", "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", @@ -891,6 +805,18 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@fast-csv/format": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", @@ -928,11 +854,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -949,7 +879,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "license": "MIT", "engines": { "node": ">=12" }, @@ -957,29 +886,10 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -996,7 +906,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -1007,29 +916,11 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, - "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -1046,7 +937,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -1056,7 +946,6 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -1066,7 +955,6 @@ "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -1084,7 +972,6 @@ "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/reporters": "^29.7.0", @@ -1127,12 +1014,32 @@ } } }, + "node_modules/@jest/core/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", @@ -1148,7 +1055,6 @@ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, - "license": "MIT", "dependencies": { "expect": "^29.7.0", "jest-snapshot": "^29.7.0" @@ -1162,7 +1068,6 @@ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, - "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3" }, @@ -1175,7 +1080,6 @@ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", @@ -1193,7 +1097,6 @@ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -1209,7 +1112,6 @@ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, - "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.7.0", @@ -1248,40 +1150,79 @@ } } }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "node_modules/@jest/reporters/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, - "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@jest/test-result": { + "node_modules/@jest/reporters/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", @@ -1297,7 +1238,6 @@ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", @@ -1313,7 +1253,6 @@ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -1340,7 +1279,6 @@ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -1358,7 +1296,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1373,7 +1310,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1383,7 +1319,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1392,15 +1327,13 @@ "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1410,7 +1343,6 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", - "license": "ISC", "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", @@ -1422,20 +1354,10 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/@npmcli/fs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", - "license": "ISC", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dependencies": { "semver": "^7.3.5" }, @@ -1443,11 +1365,21 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -1457,15 +1389,13 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } @@ -1475,7 +1405,6 @@ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0" } @@ -1484,36 +1413,31 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -1527,7 +1451,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } @@ -1537,7 +1460,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -1548,7 +1470,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } @@ -1558,7 +1479,6 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, - "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -1569,7 +1489,6 @@ "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", "dev": true, - "license": "MIT", "dependencies": { "@types/express": "*" } @@ -1579,7 +1498,6 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1589,7 +1507,6 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -1598,11 +1515,10 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -1615,7 +1531,6 @@ "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1624,15 +1539,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz", "integrity": "sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/helmet": { "version": "0.0.47", "resolved": "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.47.tgz", "integrity": "sha512-TcHA/djjdUtrMtq/QAayVLrsgjNNZ1Uhtz0KhfH01mrmjH44E54DA1A0HNbwW0H/NBFqV+tGMo85ACuEhMXcdg==", "dev": true, - "license": "MIT", "dependencies": { "@types/express": "*" } @@ -1641,8 +1554,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/http-proxy": { "version": "1.17.14", @@ -1666,15 +1578,13 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, - "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -1684,7 +1594,6 @@ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } @@ -1705,25 +1614,28 @@ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dev": true, - "license": "MIT", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" } }, + "node_modules/@types/lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/morgan": { "version": "1.9.9", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz", "integrity": "sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1732,7 +1644,6 @@ "version": "20.11.29", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz", "integrity": "sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA==", - "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } @@ -1742,7 +1653,6 @@ "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.3.tgz", "integrity": "sha512-xocw4LvpDcj/Ta7bN52tLZm34mso5SZ0Q8fVC0UtD8s85Itip3YHvBeYZhBmC0OThpdOujHsxXtRbEIRxqXPXg==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "pg-protocol": "*", @@ -1750,25 +1660,22 @@ } }, "node_modules/@types/qs": { - "version": "6.9.14", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", - "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", - "dev": true, - "license": "MIT" + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, - "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -1779,7 +1686,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -1790,35 +1696,30 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/strip-json-comments": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", - "license": "MIT" + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" }, "node_modules/@types/uuid": { "version": "9.0.8", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/xlsx": { "version": "0.0.36", @@ -1835,7 +1736,6 @@ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } @@ -1844,14 +1744,12 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/abbrev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -1860,7 +1758,6 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -1895,7 +1792,6 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -1904,7 +1800,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", - "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -1913,7 +1808,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "license": "MIT", "dependencies": { "debug": "^4.3.4" }, @@ -1922,10 +1816,9 @@ } }, "node_modules/agent-base/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -1941,14 +1834,12 @@ "node_modules/agent-base/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -1993,7 +1884,6 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -2003,7 +1893,6 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -2019,7 +1908,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -2028,24 +1916,20 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "optional": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -2056,7 +1940,6 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2069,7 +1952,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "license": "ISC", "optional": true }, "node_modules/archiver": { @@ -2109,6 +1991,26 @@ "node": ">= 6" } }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/archiver/node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", @@ -2156,7 +2058,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "license": "ISC", + "deprecated": "This package is no longer supported.", "optional": true, "dependencies": { "delegates": "^1.0.0", @@ -2167,31 +2069,33 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, + "node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -2200,7 +2104,6 @@ "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "license": "MIT", "dependencies": { "lodash": "^4.17.14" } @@ -2208,14 +2111,12 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { "version": "1.6.8", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", - "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -2227,7 +2128,6 @@ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", @@ -2249,7 +2149,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -2266,7 +2165,6 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -2283,7 +2181,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -2293,7 +2190,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -2309,7 +2205,6 @@ "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -2333,7 +2228,6 @@ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, - "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" @@ -2348,8 +2242,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -2374,7 +2267,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "license": "MIT", "dependencies": { "safe-buffer": "5.1.2" }, @@ -2394,10 +2286,12 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "license": "MIT", "dependencies": { "buffers": "~0.1.1", "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" } }, "node_modules/binary-extensions": { @@ -2405,7 +2299,6 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -2417,7 +2310,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", "optional": true, "dependencies": { "file-uri-to-path": "1.0.0" @@ -2433,7 +2325,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", - "license": "MIT", "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -2471,7 +2362,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2481,7 +2371,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "license": "MIT", "dependencies": { "fill-range": "^7.0.1" }, @@ -2508,7 +2397,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001587", "electron-to-chromium": "^1.4.668", @@ -2527,7 +2415,6 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } @@ -2559,7 +2446,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "license": "MIT", "optional": true, "dependencies": { "buffer-alloc-unsafe": "^1.1.0", @@ -2570,14 +2456,12 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "license": "MIT", "optional": true }, "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", "engines": { "node": "*" } @@ -2586,15 +2470,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", - "license": "MIT", "optional": true }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/buffer-indexof-polyfill": { "version": "1.0.2", @@ -2608,7 +2490,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.1.tgz", "integrity": "sha512-IdnyU2jDHU65U63JuVQNTHiWjPRH0CS3aYd/WPaEwyX84rFdukhOduAVb1jwUScmb5X0JWPw8NZOrhoLMiyAHQ==", - "license": "MIT", "dependencies": { "long": "1.1.2" } @@ -2639,16 +2520,14 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/cacache": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", - "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", - "license": "ISC", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", + "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -2667,66 +2546,10 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.10.2" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -2746,7 +2569,6 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -2756,15 +2578,14 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001605", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz", - "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==", + "version": "1.0.30001620", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz", + "integrity": "sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==", "dev": true, "funding": [ { @@ -2779,14 +2600,12 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/cfb": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", - "license": "Apache-2.0", "dependencies": { "adler-32": "~1.3.0", "crc-32": "~1.2.0" @@ -2799,9 +2618,11 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "license": "MIT/X11", "dependencies": { "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" } }, "node_modules/chalk": { @@ -2809,7 +2630,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2821,12 +2641,26 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } @@ -2836,7 +2670,6 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -2857,13 +2690,10 @@ } }, "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "license": "ISC", - "engines": { - "node": ">=10" - } + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "optional": true }, "node_modules/ci-info": { "version": "3.9.0", @@ -2876,23 +2706,20 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true, - "license": "MIT" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "dev": true }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "license": "MIT", "engines": { "node": ">=6" } @@ -2902,7 +2729,6 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -2912,12 +2738,41 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/cliui/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -2927,7 +2782,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2937,21 +2791,56 @@ "node": ">=8" } }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "license": "MIT", "engines": { "node": ">=0.8" } }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, - "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -2961,7 +2850,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", - "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -2971,7 +2859,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", - "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -2980,14 +2867,12 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "license": "MIT", "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" @@ -2997,7 +2882,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3008,14 +2892,12 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/color-string": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "license": "MIT", "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -3025,7 +2907,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -3033,14 +2914,12 @@ "node_modules/color/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/colorspace": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "license": "MIT", "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" @@ -3050,7 +2929,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3089,7 +2967,6 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -3101,7 +2978,6 @@ "version": "1.7.4", "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -3119,7 +2995,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3127,21 +3002,18 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "license": "ISC", "optional": true }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -3166,14 +3038,12 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3182,8 +3052,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/cookie": { "version": "0.6.0", @@ -3196,20 +3065,17 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "node_modules/crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "license": "Apache-2.0", "bin": { "crc32": "bin/crc32.njs" }, @@ -3247,7 +3113,6 @@ "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -3268,14 +3133,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3285,6 +3148,20 @@ "node": ">= 8" } }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/dayjs": { "version": "1.11.11", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", @@ -3294,7 +3171,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -3303,7 +3179,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "license": "MIT", "optional": true, "dependencies": { "mimic-response": "^1.0.0" @@ -3313,11 +3188,10 @@ } }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, - "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -3331,7 +3205,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", "optional": true, "engines": { "node": ">=4.0.0" @@ -3340,15 +3213,13 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "license": "MIT" + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3357,7 +3228,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -3374,7 +3244,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -3383,14 +3252,12 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "license": "MIT", "optional": true }, "node_modules/denque": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", - "license": "Apache-2.0", "engines": { "node": ">=0.10" } @@ -3399,7 +3266,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3408,7 +3274,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -3418,7 +3283,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "license": "Apache-2.0", "optional": true, "bin": { "detect-libc": "bin/detect-libc.js" @@ -3432,7 +3296,6 @@ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -3442,7 +3305,6 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -3452,7 +3314,6 @@ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, - "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -3462,7 +3323,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -3483,7 +3343,6 @@ "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", "dev": true, - "license": "MIT", "dependencies": { "xtend": "^4.0.0" } @@ -3491,26 +3350,24 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.726", - "dev": true, - "license": "ISC" + "version": "1.4.772", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.772.tgz", + "integrity": "sha512-jFfEbxR/abTTJA3ci+2ok1NTuOBBtB4jH+UT6PUmRN+DY3WSD4FFRsgoVQ+QNIJ0T7wrXwzsWCI2WKC46b++2A==", + "dev": true }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -3519,22 +3376,19 @@ } }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", - "license": "MIT" + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3543,7 +3397,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -3553,7 +3406,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -3566,7 +3418,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "license": "MIT", "dependencies": { "once": "^1.4.0" } @@ -3576,7 +3427,6 @@ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -3585,11 +3435,31 @@ "node": ">=8.6" } }, + "node_modules/enquirer/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/enquirer/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "license": "MIT", "engines": { "node": ">=6" } @@ -3597,8 +3467,7 @@ "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "license": "MIT" + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" }, "node_modules/error": { "version": "7.0.2", @@ -3614,16 +3483,20 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, - "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, + "node_modules/error-ex/node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -3635,7 +3508,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", "engines": { "node": ">= 0.4" } @@ -3645,7 +3517,6 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -3653,14 +3524,21 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } }, "node_modules/escodegen": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", "estraverse": "^4.2.0", @@ -3678,54 +3556,16 @@ "source-map": "~0.6.1" } }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "license": "MIT", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2" + "node_modules/escodegen/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">= 0.8.0" + "node": ">=4" } }, "node_modules/eslint": { @@ -3787,7 +3627,6 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -3801,7 +3640,6 @@ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, - "license": "MIT", "dependencies": { "eslint-visitor-keys": "^1.1.0" }, @@ -3817,7 +3655,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=4" } @@ -3827,7 +3664,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10" } @@ -3848,12 +3684,20 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -3872,12 +3716,98 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/eslint/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "license": "MIT" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } }, "node_modules/espree": { "version": "7.3.1", @@ -3903,16 +3833,15 @@ } }, "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=4" + "node": ">=0.4.0" } }, "node_modules/esquery": { @@ -3920,7 +3849,6 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -3933,7 +3861,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3943,7 +3870,6 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -3956,7 +3882,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3965,7 +3890,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3974,7 +3898,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -3983,7 +3906,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4038,7 +3960,6 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -4070,7 +3991,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", "optional": true, "engines": { "node": ">=6" @@ -4081,7 +4001,6 @@ "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", @@ -4096,8 +4015,7 @@ "node_modules/exponential-backoff": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "license": "Apache-2.0" + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" }, "node_modules/express": { "version": "4.19.2", @@ -4157,8 +4075,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/fast-csv": { "version": "4.3.6", @@ -4175,28 +4092,24 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "license": "MIT" + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } @@ -4204,15 +4117,13 @@ "node_modules/fecha": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", - "license": "MIT" + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -4224,14 +4135,12 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT", "optional": true }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4243,7 +4152,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -4262,7 +4170,6 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -4276,7 +4183,6 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, - "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -4290,14 +4196,12 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/fn.name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", - "license": "MIT" + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "node_modules/follow-redirects": { "version": "1.15.6", @@ -4309,7 +4213,6 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], - "license": "MIT", "engines": { "node": ">=4.0" }, @@ -4320,10 +4223,9 @@ } }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "license": "ISC", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz", + "integrity": "sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -4339,7 +4241,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", "engines": { "node": ">=14" }, @@ -4351,7 +4252,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -4365,7 +4265,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4374,7 +4273,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", - "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -4383,7 +4281,6 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4391,14 +4288,12 @@ "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -4409,8 +4304,21 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, "node_modules/fstream": { "version": "1.0.12", @@ -4427,6 +4335,26 @@ "node": ">=0.6" } }, + "node_modules/fstream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fstream/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -4443,7 +4371,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4452,14 +4379,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", - "license": "ISC", + "deprecated": "This package is no longer supported.", "optional": true, "dependencies": { "aproba": "^1.0.3", @@ -4472,35 +4398,11 @@ "wide-align": "^1.1.0" } }, - "node_modules/gauge/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "license": "MIT", - "optional": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -4510,7 +4412,6 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, - "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -4519,7 +4420,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -4539,7 +4439,6 @@ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -4549,7 +4448,6 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -4561,24 +4459,24 @@ "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT", "optional": true }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "license": "ISC", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4589,7 +4487,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -4597,6 +4494,28 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { "version": "12.4.0", "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", @@ -4612,11 +4531,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -4627,15 +4554,13 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -4644,7 +4569,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -4656,7 +4580,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4668,7 +4591,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4680,20 +4602,17 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "license": "ISC", "optional": true }, "node_modules/hash-sum": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", - "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", - "license": "MIT" + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==" }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -4705,7 +4624,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", - "license": "MIT", "engines": { "node": ">=16.0.0" } @@ -4731,20 +4649,17 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "license": "BSD-2-Clause" + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -4773,7 +4688,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "license": "MIT", "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -4783,10 +4697,9 @@ } }, "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -4802,8 +4715,7 @@ "node_modules/http-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/http-proxy-middleware": { "version": "3.0.0", @@ -4846,7 +4758,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", - "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -4856,10 +4767,9 @@ } }, "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -4875,15 +4785,13 @@ "node_modules/https-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -4892,7 +4800,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -4931,8 +4838,7 @@ "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -4955,7 +4861,6 @@ "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, - "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -4974,7 +4879,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -4983,7 +4887,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "license": "MIT", "engines": { "node": ">=8" } @@ -4992,7 +4895,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "license": "ISC", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -5001,57 +4904,96 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC", "optional": true }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "license": "MIT", + "node_modules/ioredis": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.4.1.tgz", + "integrity": "sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==", "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" }, "engines": { - "node": ">= 12" + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" } }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "license": "BSD-3-Clause" + "node_modules/ioredis/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ioredis/node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/ioredis/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -5064,7 +5006,6 @@ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, - "license": "MIT", "dependencies": { "hasown": "^2.0.0" }, @@ -5076,7 +5017,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5085,7 +5025,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", - "license": "MIT", "optional": true, "dependencies": { "number-is-nan": "^1.0.0" @@ -5099,7 +5038,6 @@ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -5108,7 +5046,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -5119,14 +5056,12 @@ "node_modules/is-lambda": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "license": "MIT" + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -5146,7 +5081,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", "engines": { "node": ">=8" }, @@ -5157,21 +5091,18 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=8" } @@ -5181,7 +5112,6 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -5193,12 +5123,23 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -5213,7 +5154,6 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -5228,7 +5168,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -5245,15 +5184,13 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/istanbul-reports": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -5263,10 +5200,9 @@ } }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "license": "BlueOak-1.0.0", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -5308,7 +5244,6 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -5335,7 +5270,6 @@ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, - "license": "MIT", "dependencies": { "execa": "^5.0.0", "jest-util": "^29.7.0", @@ -5345,12 +5279,26 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-changed-files/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jest-circus": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -5377,38 +5325,19 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "node_modules/jest-circus/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "license": "MIT", "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "node": ">=10" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/jest-config": { @@ -5416,7 +5345,6 @@ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.7.0", @@ -5457,12 +5385,44 @@ } } }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jest-diff": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", @@ -5478,7 +5438,6 @@ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, - "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" }, @@ -5491,7 +5450,6 @@ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -5508,7 +5466,6 @@ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -5526,7 +5483,6 @@ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, - "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -5536,7 +5492,6 @@ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -5562,7 +5517,6 @@ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, - "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" @@ -5576,7 +5530,6 @@ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.7.0", @@ -5592,7 +5545,6 @@ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -5608,26 +5560,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-message-util/node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/jest-mock": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -5642,7 +5579,6 @@ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" }, @@ -5660,7 +5596,6 @@ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, - "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -5670,7 +5605,6 @@ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -5691,7 +5625,6 @@ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, - "license": "MIT", "dependencies": { "jest-regex-util": "^29.6.3", "jest-snapshot": "^29.7.0" @@ -5705,7 +5638,6 @@ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/environment": "^29.7.0", @@ -5733,12 +5665,26 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runner/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jest-runtime": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -5767,12 +5713,32 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-snapshot": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -5799,12 +5765,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -5822,7 +5799,6 @@ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -5840,7 +5816,6 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -5853,7 +5828,6 @@ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, - "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", @@ -5873,7 +5847,6 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", @@ -5889,7 +5862,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -5900,19 +5872,50 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jest/node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -5921,18 +5924,29 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { + "node_modules/js-yaml/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jsbn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "license": "MIT" + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, - "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -5944,15 +5958,13 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-schema-traverse": { "version": "1.0.0", @@ -5963,15 +5975,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -5983,30 +5993,16 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", - "license": "MIT", "dependencies": { "esprima": "1.2.2", "static-eval": "2.0.2", "underscore": "1.12.1" } }, - "node_modules/jsonpath/node_modules/esprima": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", - "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -6018,7 +6014,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz", "integrity": "sha512-dD2ga5gLcQhsq1yNoQdy1MU4x4z7YnXM5bcG9SdQuiNr5KKuAmXixH1Mggwdah5o7EfholFbcNDPSVA6BIfaug==", - "license": "MIT", "dependencies": { "async": "^2.6.2", "binary": "~0.3.0", @@ -6045,7 +6040,7 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "license": "MIT", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "bin": { "uuid": "bin/uuid" } @@ -6055,7 +6050,6 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -6065,7 +6059,6 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -6073,8 +6066,7 @@ "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", - "license": "MIT" + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, "node_modules/lazystream": { "version": "1.0.1", @@ -6092,20 +6084,17 @@ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" }, "engines": { "node": ">= 0.8.0" @@ -6115,7 +6104,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", "dependencies": { "immediate": "~3.0.5" } @@ -6124,8 +6112,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/listenercount": { "version": "1.0.1", @@ -6137,7 +6124,6 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, - "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -6148,8 +6134,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.defaults": { "version": "4.2.0", @@ -6176,6 +6161,11 @@ "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==" }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", @@ -6210,8 +6200,7 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/lodash.union": { "version": "4.6.0", @@ -6227,7 +6216,6 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "license": "MIT", "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -6243,26 +6231,22 @@ "node_modules/logform/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/long": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/long/-/long-1.1.2.tgz", "integrity": "sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q==", - "license": "Apache-2.0", "engines": { "node": ">=0.6" } }, "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "engines": { + "node": "14 || >=16.14" } }, "node_modules/make-dir": { @@ -6270,7 +6254,6 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, - "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -6281,18 +6264,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/make-fetch-happen": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", - "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", - "license": "ISC", + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", @@ -6303,6 +6296,7 @@ "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", + "proc-log": "^4.2.0", "promise-retry": "^2.0.1", "ssri": "^10.0.0" }, @@ -6310,12 +6304,19 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/make-fetch-happen/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } @@ -6324,7 +6325,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6332,21 +6332,18 @@ "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "license": "MIT" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6355,7 +6352,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "license": "MIT", "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -6368,7 +6364,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", "bin": { "mime": "cli.js" }, @@ -6380,7 +6375,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6389,7 +6383,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -6402,7 +6395,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -6411,7 +6403,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "license": "MIT", "optional": true, "engines": { "node": ">=4" @@ -6421,7 +6412,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6433,16 +6423,14 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "license": "ISC", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "engines": { "node": ">=16 || 14 >=14.17" } @@ -6451,7 +6439,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -6460,10 +6447,9 @@ } }, "node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "license": "MIT", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -6480,7 +6466,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6492,7 +6477,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6500,17 +6484,10 @@ "node": ">=8" } }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6522,7 +6499,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6530,17 +6506,10 @@ "node": ">=8" } }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6552,7 +6521,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6560,17 +6528,10 @@ "node": ">=8" } }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -6583,7 +6544,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6591,17 +6551,10 @@ "node": ">=8" } }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, @@ -6613,7 +6566,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", - "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", @@ -6629,7 +6581,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -6640,35 +6591,30 @@ "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/nan": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", - "license": "MIT", "optional": true }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "license": "MIT", "optional": true }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6676,34 +6622,21 @@ "node_modules/nested-error-stacks": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", - "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", - "license": "MIT" + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" }, "node_modules/node-abi": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "license": "MIT", "optional": true, "dependencies": { "semver": "^5.4.1" } }, - "node_modules/node-abi/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/node-cache": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", - "license": "MIT", "dependencies": { "clone": "2.x" }, @@ -6734,101 +6667,38 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/node-gyp/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/node-gyp/node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.10.2" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { - "node-which": "bin/which.js" + "semver": "bin/semver.js" }, "engines": { - "node": "^16.13.0 || >=18.0.0" + "node": ">=10" } }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "license": "MIT" + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==", - "license": "MIT", "optional": true }, "node_modules/nopt": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", - "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", - "license": "ISC", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "dependencies": { "abbrev": "^2.0.0" }, @@ -6843,7 +6713,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6853,7 +6722,6 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -6865,7 +6733,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "license": "ISC", + "deprecated": "This package is no longer supported.", "optional": true, "dependencies": { "are-we-there-yet": "~1.1.2", @@ -6878,7 +6746,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", - "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -6888,7 +6755,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -6898,7 +6764,6 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6907,14 +6772,12 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -6926,7 +6789,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -6935,7 +6797,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", "dependencies": { "wrappy": "1" } @@ -6944,7 +6805,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "license": "MIT", "dependencies": { "fn.name": "1.x.x" } @@ -6954,7 +6814,6 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, - "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -6976,22 +6835,19 @@ "node_modules/optional": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz", - "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==", - "license": "MIT" + "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==" }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "license": "MIT", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" }, "engines": { "node": ">= 0.8.0" @@ -7001,23 +6857,21 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, - "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7028,7 +6882,6 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -7036,27 +6889,10 @@ "node": ">=8" } }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-map": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -7072,7 +6908,6 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -7080,8 +6915,7 @@ "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "node_modules/parent-module": { "version": "1.0.1", @@ -7100,7 +6934,6 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -7118,7 +6951,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -7128,7 +6960,6 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -7137,7 +6968,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7146,7 +6976,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", "engines": { "node": ">=8" } @@ -7155,39 +6984,27 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/path-scurry": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", - "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", - "license": "BlueOak-1.0.0", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "license": "MIT" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "node_modules/pg": { "version": "8.12.0", @@ -7221,22 +7038,19 @@ "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", "dev": true, - "license": "MIT", "optional": true }, "node_modules/pg-connection-string": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", "dev": true, - "license": "ISC", "engines": { "node": ">=4.0.0" } @@ -7246,7 +7060,6 @@ "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", "dev": true, - "license": "ISC", "engines": { "node": ">=4" } @@ -7256,7 +7069,6 @@ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", "dev": true, - "license": "MIT", "peerDependencies": { "pg": ">=8.0" } @@ -7265,15 +7077,13 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/pg-types": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", "dev": true, - "license": "MIT", "dependencies": { "pg-int8": "1.0.1", "pg-numeric": "1.0.2", @@ -7292,7 +7102,6 @@ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", "dev": true, - "license": "MIT", "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", @@ -7309,7 +7118,6 @@ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -7319,7 +7127,6 @@ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7329,7 +7136,6 @@ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7339,7 +7145,6 @@ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", "dev": true, - "license": "MIT", "dependencies": { "xtend": "^4.0.0" }, @@ -7352,23 +7157,20 @@ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", "dev": true, - "license": "MIT", "dependencies": { "split2": "^4.1.0" } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true, - "license": "ISC" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "license": "MIT", "engines": { "node": ">=8.6" }, @@ -7381,7 +7183,6 @@ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 6" } @@ -7391,7 +7192,6 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, - "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -7404,7 +7204,6 @@ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } @@ -7414,7 +7213,6 @@ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", "dev": true, - "license": "MIT", "dependencies": { "obuf": "~1.1.2" }, @@ -7427,7 +7225,6 @@ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } @@ -7437,7 +7234,6 @@ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } @@ -7446,14 +7242,12 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/prebuild-install": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz", "integrity": "sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg==", - "license": "MIT", "optional": true, "dependencies": { "detect-libc": "^1.0.3", @@ -7481,11 +7275,9 @@ } }, "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "engines": { "node": ">= 0.8.0" } @@ -7495,7 +7287,6 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -7510,7 +7301,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -7522,7 +7312,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -7538,15 +7327,13 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -7567,7 +7354,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "license": "MIT", "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -7580,7 +7366,6 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "license": "MIT", "engines": { "node": ">= 4" } @@ -7590,7 +7375,6 @@ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, - "license": "MIT", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -7602,14 +7386,12 @@ "node_modules/property-expr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", - "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", - "license": "MIT" + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -7621,14 +7403,12 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "license": "MIT", "optional": true, "dependencies": { "end-of-stream": "^1.1.0", @@ -7639,7 +7419,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "license": "MIT", "engines": { "node": ">=6" } @@ -7658,14 +7437,12 @@ "type": "opencollective", "url": "https://opencollective.com/fast-check" } - ], - "license": "MIT" + ] }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -7680,7 +7457,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7689,7 +7465,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -7704,7 +7479,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "optional": true, "dependencies": { "deep-extend": "^0.6.0", @@ -7716,28 +7490,16 @@ "rc": "cli.js" } }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7780,7 +7542,6 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -7788,12 +7549,30 @@ "node": ">=8.10.0" } }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -7806,7 +7585,6 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7815,7 +7593,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7830,7 +7607,6 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, - "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -7848,7 +7624,6 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, - "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -7861,7 +7636,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -7880,7 +7654,6 @@ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } @@ -7889,7 +7662,6 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", "integrity": "sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ==", - "license": "MIT", "engines": { "node": "*" } @@ -7898,8 +7670,8 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -7910,17 +7682,36 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safe-stable-stringify": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "license": "MIT", "engines": { "node": ">=10" } @@ -7928,14 +7719,12 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sax": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", - "license": "ISC" + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" }, "node_modules/saxes": { "version": "5.0.1", @@ -7949,43 +7738,18 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true, "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "semver": "bin/semver" } }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -8008,14 +7772,12 @@ "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -8030,14 +7792,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC", "optional": true }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -8053,20 +7813,17 @@ "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -8078,7 +7835,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", "engines": { "node": ">=8" } @@ -8087,7 +7843,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -8105,8 +7860,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "devOptional": true, - "license": "ISC" + "devOptional": true }, "node_modules/simple-concat": { "version": "1.0.1", @@ -8126,14 +7880,12 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "optional": true }, "node_modules/simple-get": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", - "license": "MIT", "optional": true, "dependencies": { "decompress-response": "^3.3.0", @@ -8145,30 +7897,21 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "license": "MIT", "dependencies": { "is-arrayish": "^0.3.1" } }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT" - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -8178,7 +7921,6 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -8191,12 +7933,26 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -8205,7 +7961,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -8216,7 +7971,6 @@ "resolved": "https://registry.npmjs.org/snappy/-/snappy-6.3.5.tgz", "integrity": "sha512-lonrUtdp1b1uDn1dbwgQbBsb5BbaiLeKq+AGwOk2No+en+VvJThwmtztwulEQsLinRF681pBqib0NUZaizKLIA==", "hasInstallScript": true, - "license": "MIT", "optional": true, "dependencies": { "bindings": "^1.3.1", @@ -8225,10 +7979,9 @@ } }, "node_modules/socks": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", - "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", - "license": "MIT", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -8242,7 +7995,6 @@ "version": "8.0.3", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", - "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", @@ -8253,10 +8005,9 @@ } }, "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -8272,15 +8023,13 @@ "node_modules/socks-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "devOptional": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -8290,7 +8039,6 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, - "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -8301,23 +8049,19 @@ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, - "license": "ISC", "engines": { "node": ">= 10.x" } }, "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/ssf": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", - "license": "Apache-2.0", "dependencies": { "frac": "~1.1.2" }, @@ -8326,10 +8070,9 @@ } }, "node_modules/ssri": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", - "license": "ISC", + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", "dependencies": { "minipass": "^7.0.3" }, @@ -8341,7 +8084,6 @@ "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "license": "MIT", "engines": { "node": "*" } @@ -8351,7 +8093,6 @@ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, - "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -8364,16 +8105,19 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "node_modules/static-eval": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", - "license": "MIT", "dependencies": { "escodegen": "^1.8.1" } @@ -8382,7 +8126,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8391,7 +8134,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -8401,7 +8143,6 @@ "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, - "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -8410,6 +8151,27 @@ "node": ">=10" } }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", @@ -8419,7 +8181,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", - "license": "MIT", "optional": true, "dependencies": { "code-point-at": "^1.0.0", @@ -8435,40 +8196,48 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" - }, + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "engines": { "node": ">=8" } }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "license": "MIT", - "optional": true, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/string-width/node_modules/strip-ansi": { + "node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "license": "MIT", "optional": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -8477,27 +8246,19 @@ "node": ">=0.10.0" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" - }, + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "engines": { "node": ">=8" } @@ -8507,7 +8268,6 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -8517,22 +8277,17 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/supports-color": { @@ -8540,7 +8295,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -8553,7 +8307,6 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -8566,7 +8319,6 @@ "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "ajv": "^8.0.1", "lodash.truncate": "^4.4.2", @@ -8578,12 +8330,26 @@ "node": ">=10.0.0" } }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/table/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -8593,7 +8359,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -8603,11 +8368,22 @@ "node": ">=8" } }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tar": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -8624,7 +8400,6 @@ "version": "1.16.3", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", - "license": "MIT", "optional": true, "dependencies": { "chownr": "^1.0.1", @@ -8633,18 +8408,10 @@ "tar-stream": "^1.1.2" } }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC", - "optional": true - }, "node_modules/tar-fs/node_modules/pump": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "license": "MIT", "optional": true, "dependencies": { "end-of-stream": "^1.1.0", @@ -8655,7 +8422,6 @@ "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "license": "MIT", "optional": true, "dependencies": { "bl": "^1.0.0", @@ -8674,18 +8440,24 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "license": "MIT", "optional": true, "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" } }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/tar/node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -8697,7 +8469,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -8709,7 +8480,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", "engines": { "node": ">=8" } @@ -8718,7 +8488,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -8726,12 +8495,6 @@ "node": ">=10" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/tdigest": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", @@ -8746,7 +8509,6 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, - "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -8756,18 +8518,37 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", - "license": "MIT" + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/thriftrw": { "version": "3.11.4", @@ -8796,8 +8577,7 @@ "node_modules/tiny-case": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", - "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", - "license": "MIT" + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" }, "node_modules/tmp": { "version": "0.2.3", @@ -8811,14 +8591,12 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "license": "MIT", "optional": true }, "node_modules/to-fast-properties": { @@ -8826,7 +8604,6 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -8835,7 +8612,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -8847,7 +8623,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", "engines": { "node": ">=0.6" } @@ -8855,21 +8630,21 @@ "node_modules/toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", - "license": "MIT" + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" }, "node_modules/traverse": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "license": "MIT/X11" + "engines": { + "node": "*" + } }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, - "license": "MIT", "bin": { "tree-kill": "cli.js" } @@ -8878,7 +8653,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "license": "MIT", "engines": { "node": ">= 14.0.0" } @@ -8888,7 +8662,6 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, - "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -8932,7 +8705,6 @@ "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", "dev": true, - "license": "MIT", "dependencies": { "chokidar": "^3.5.1", "dynamic-dedupe": "^0.3.0", @@ -8962,12 +8734,32 @@ } } }, + "node_modules/ts-node-dev/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ts-node-dev/node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -8979,8 +8771,8 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -8993,7 +8785,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -9006,7 +8797,6 @@ "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", "dev": true, - "license": "MIT", "dependencies": { "@types/strip-bom": "^3.0.0", "@types/strip-json-comments": "0.0.30", @@ -9019,26 +8809,14 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/tsconfig/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", "optional": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -9048,13 +8826,11 @@ } }, "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "dependencies": { - "prelude-ls": "^1.2.1" + "prelude-ls": "~1.1.2" }, "engines": { "node": ">= 0.8.0" @@ -9065,25 +8841,25 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "engines": { - "node": ">=8" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -9097,7 +8873,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9109,20 +8884,17 @@ "node_modules/underscore": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", - "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", - "license": "MIT" + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "license": "MIT" + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unique-filename": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -9134,7 +8906,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -9146,7 +8917,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9169,9 +8939,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", "dev": true, "funding": [ { @@ -9187,10 +8957,9 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -9203,7 +8972,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -9211,14 +8979,12 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -9231,7 +8997,6 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -9240,22 +9005,19 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/v8-to-istanbul": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", "dev": true, - "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -9269,7 +9031,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9279,41 +9040,45 @@ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } }, "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dependencies": { - "isexe": "^2.0.0" + "isexe": "^3.1.1" }, "bin": { - "node-which": "bin/node-which" + "node-which": "bin/which.js" }, "engines": { - "node": ">= 8" + "node": "^16.13.0 || >=18.0.0" } }, "node_modules/which-pm-runs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", - "license": "MIT", "optional": true, "engines": { "node": ">=4" } }, + "node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "engines": { + "node": ">=16" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "license": "ISC", "optional": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" @@ -9323,7 +9088,6 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz", "integrity": "sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w==", - "license": "MIT", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", @@ -9345,7 +9109,6 @@ "version": "4.7.0", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "license": "MIT", "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", @@ -9359,7 +9122,6 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9372,14 +9134,12 @@ "node_modules/winston/node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "license": "MIT" + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, "node_modules/winston/node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9393,7 +9153,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", - "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -9402,7 +9161,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", - "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -9411,24 +9169,21 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -9439,24 +9194,43 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", "engines": { "node": ">=8" } @@ -9465,7 +9239,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9475,43 +9248,68 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { "node": ">=8" } }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -9544,7 +9342,6 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz", "integrity": "sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw==", - "license": "MIT", "dependencies": { "cfb": "^1.1.3", "jszip": "^3.2.2", @@ -9566,7 +9363,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", "engines": { "node": ">=0.4" } @@ -9576,24 +9372,20 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, - "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, - "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -9612,17 +9404,30 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "license": "ISC", "engines": { "node": ">=12" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/yargs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -9632,7 +9437,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9642,12 +9446,23 @@ "node": ">=8" } }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -9657,7 +9472,6 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -9669,7 +9483,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz", "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==", - "license": "MIT", "dependencies": { "property-expr": "^2.0.5", "tiny-case": "^1.0.3", @@ -9677,18 +9490,6 @@ "type-fest": "^2.19.0" } }, - "node_modules/yup/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/zip-stream": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", @@ -9722,6 +9523,26 @@ "node": ">= 10" } }, + "node_modules/zip-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/zip-stream/node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", diff --git a/health-services/project-factory/package.json b/health-services/project-factory/package.json index a91771378fa..31dd40bc152 100644 --- a/health-services/project-factory/package.json +++ b/health-services/project-factory/package.json @@ -1,6 +1,6 @@ { "name": "project-factory", - "version": "0.1.0", + "version": "0.2.0", "main": "src/server/index.ts", "author": "Jagankumar ", "description": "Backend For Frontend service", @@ -54,6 +54,7 @@ "@types/http-proxy-middleware": "^1.0.0", "@types/jaeger-client": "^3.18.7", "@types/jest": "29.5.12", + "@types/lodash": "^4.17.5", "@types/morgan": "1.9.9", "@types/node": "20.11.29", "@types/pg": "8.11.3", diff --git a/health-services/project-factory/postman_collection.json b/health-services/project-factory/postman_collection.json index 5780448766a..d99524df3c1 100644 --- a/health-services/project-factory/postman_collection.json +++ b/health-services/project-factory/postman_collection.json @@ -1,18 +1,13 @@ { "info": { - "_postman_id": "4faeccce-fc50-4dfb-8fef-d973aca136c4", - "name": "Project factory", + "_postman_id": "42be4494-a788-4977-b8f2-e14894cce42b", + "name": "Project-Factory Collection", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "18845214" + "_exporter_id": "28207698" }, "item": [ { - "name": "facility data generate(template generate)", - "protocolProfileBehavior": { - "disabledSystemHeaders": { - "content-type": true - } - }, + "name": "campain-manage-create Copy", "request": { "method": "POST", "header": [ @@ -30,8 +25,7 @@ }, { "key": "content-type", - "value": "application/json", - "disabled": true + "value": "application/json" }, { "key": "cookie", @@ -72,65 +66,37 @@ { "key": "user-agent", "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" } ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\":{\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"b902a184-4582-41f8-8144-99930548631d\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1716457221446|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" + "raw": "{\n // 43cfaf3f-f31f-492f-afeb-cebe4f4301e8\n // d71a1963-27a8-4300-a1c4-2ec99e95331b multiplesheet\n // 6c091ddb-523e-4afd-8a81-afe94196d080 without matching sheetName\n // for unifieddev\n // 1d27af7d-3736-408d-b9bc-796c92fd5f4b multiplesheet\n \"Campaign\": {\n // \"id\": \"string\",\n // \"campaignNo\": \"string\",\n \"hierarchyType\": \"string\",\n \"tenantId\": \"mz\",\n \"campaignName\": \"string\",\n \"boundaryCode\": \"mz\",\n \"startDate\": 1677594987,\n // \"endDate\": 9776881655,\n \"endDate\": 1677594987,\n \"projectType\": \"Household Based Project\",\n \"CampaignDetails\": [\n {\n \"boundaryCode\": \"f5F6xAskA05\",\n \"boundaryType\": \"Provincia\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 300,\n \"target\": 250,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": \"mz\",\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n \"867ba408-1b82-4746-8274-eb916e625fea\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"staff\"\n }\n ]\n },\n {\n \"boundaryCode\": \"f5F6xAskA05\",\n \"boundaryType\": \"Provincia\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 700,\n \"target\": 600,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": \"mz\",\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n \"867ba408-1b82-4746-8274-eb916e625fea\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"staff\"\n }\n ]\n },\n {\n \"boundaryCode\": \"mz\",\n \"boundaryType\": \"Country\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 1000,\n \"target\": 800,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": null,\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n \"F-2024-03-21-000882\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"facility\"\n }\n ]\n },\n {\n \"boundaryCode\": \"mz\",\n \"boundaryType\": \"Country\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 450,\n \"target\": 350,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": null,\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n // \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\"\n \"PVAR-2024-03-21-000052\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"resource\"\n // \"type\": \"staff|resource|facility\"\n }\n ]\n }\n // Add more entries as needed...\n ],\n \"deliveryRules\": [\n {\n \"startDate\": \"string\",\n \"endDate\": \"string\",\n \"cycle\": \"string\"\n }\n ],\n \"additionalDetails\": {}\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"e45445a1-6891-4a76-a4e6-528e1dd24946\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1710912592752|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" }, "url": { - "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=boundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=3b331cd6-c0e9-4fd4-9d15-9212ba51706c", - "protocol": "https", + "raw": "http://localhost:8080/project-factory/v1/project-type/createCampaign", + "protocol": "http", "host": [ - "unified-uat", - "digit", - "org" + "localhost" ], + "port": "8080", "path": [ "project-factory", "v1", - "data", - "_generate" - ], - "query": [ - { - "key": "tenantId", - "value": "mz" - }, - { - "key": "type", - "value": "boundary" - }, - { - "key": "forceUpdate", - "value": "true" - }, - { - "key": "hierarchyType", - "value": "ADMIN" - }, - { - "key": "campaignId", - "value": "3b331cd6-c0e9-4fd4-9d15-9212ba51706c" - } + "project-type", + "createCampaign" ] } }, "response": [] }, { - "name": "boundary data generate(template generate)", + "name": "mdms bulk search Copy", "request": { "method": "POST", "header": [ { "key": "authority", - "value": "unified-uat.digit.org" + "value": "unified-dev.digit.org" }, { "key": "accept", @@ -142,19 +108,19 @@ }, { "key": "content-type", - "value": "application/json;charset=UTF-8" + "value": "application/json" }, { "key": "cookie", - "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0; PGADMIN_LANGUAGE=en" + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" }, { "key": "origin", - "value": "https://unified-uat.digit.org" + "value": "https://unified-dev.digit.org" }, { "key": "referer", - "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?key=7&preview=false&id=2c948509-4245-4df7-b46b-9cabd5cdb577" + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" }, { "key": "sec-ch-ua", @@ -187,21 +153,20 @@ ], "body": { "mode": "raw", - "raw": "{\"Filters\":null,\"RequestInfo\":{\"apiId\":\"Rainmaker\",\"authToken\":\"f364ac54-8e9a-49ec-8aff-a3df278bd68d\",\"userInfo\":{\"id\":1052,\"uuid\":\"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\"userName\":\"UATMZ\",\"name\":\"UATMZ\",\"mobileNumber\":\"8998988112\",\"emailId\":null,\"locale\":null,\"type\":\"EMPLOYEE\",\"roles\":[{\"name\":\"System Administrator\",\"code\":\"SYSTEM_ADMINISTRATOR\",\"tenantId\":\"mz\"},{\"name\":\"Campaign Manager\",\"code\":\"CAMPAIGN_MANAGER\",\"tenantId\":\"mz\"},{\"name\":\"Localisation admin\",\"code\":\"LOC_ADMIN\",\"tenantId\":\"mz\"},{\"name\":\"MDMS ADMIN\",\"code\":\"MDMS_ADMIN\",\"tenantId\":\"mz\"}],\"active\":true,\"tenantId\":\"mz\",\"permanentCity\":null},\"msgId\":\"1716892389916|en_IN\",\"plainAccessRequest\":{}}}" + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1710912592752|en_MZ\",\n \"plainAccessRequest\": {}\n }\n}" }, "url": { - "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=boundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=2c948509-4245-4df7-b46b-9cabd5cdb577", - "protocol": "https", + "raw": "http://localhost:8080/mdms-bff/v1/mdmsbulk/search?tenantId=mz&schemaName=Dummy.dummy", + "protocol": "http", "host": [ - "unified-uat", - "digit", - "org" + "localhost" ], + "port": "8080", "path": [ - "project-factory", + "mdms-bff", "v1", - "data", - "_generate" + "mdmsbulk", + "search" ], "query": [ { @@ -209,20 +174,8 @@ "value": "mz" }, { - "key": "type", - "value": "boundary" - }, - { - "key": "forceUpdate", - "value": "true" - }, - { - "key": "hierarchyType", - "value": "ADMIN" - }, - { - "key": "campaignId", - "value": "2c948509-4245-4df7-b46b-9cabd5cdb577" + "key": "schemaName", + "value": "Dummy.dummy" } ] } @@ -230,7 +183,12 @@ "response": [] }, { - "name": "User generate data(template generate)", + "name": "campaign-generate Copy", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, "request": { "method": "POST", "header": [ @@ -260,7 +218,7 @@ }, { "key": "referer", - "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?key=7&preview=false&id=2c948509-4245-4df7-b46b-9cabd5cdb577" + "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?id=22f77798-3645-44b3-98ee-cc5c0ff2888c&draft=true&fetchBoundary=true&key=8&preview=false&skip=false" }, { "key": "sec-ch-ua", @@ -293,16 +251,15 @@ ], "body": { "mode": "raw", - "raw": "{\"RequestInfo\":{\"apiId\":\"Rainmaker\",\"authToken\":\"f364ac54-8e9a-49ec-8aff-a3df278bd68d\",\"userInfo\":{\"id\":1052,\"uuid\":\"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\"userName\":\"UATMZ\",\"name\":\"UATMZ\",\"mobileNumber\":\"8998988112\",\"emailId\":null,\"locale\":null,\"type\":\"EMPLOYEE\",\"roles\":[{\"name\":\"System Administrator\",\"code\":\"SYSTEM_ADMINISTRATOR\",\"tenantId\":\"mz\"},{\"name\":\"Campaign Manager\",\"code\":\"CAMPAIGN_MANAGER\",\"tenantId\":\"mz\"},{\"name\":\"Localisation admin\",\"code\":\"LOC_ADMIN\",\"tenantId\":\"mz\"},{\"name\":\"MDMS ADMIN\",\"code\":\"MDMS_ADMIN\",\"tenantId\":\"mz\"}],\"active\":true,\"tenantId\":\"mz\",\"permanentCity\":null},\"msgId\":\"1716892389917|en_IN\",\"plainAccessRequest\":{}}}" + "raw": "{\n \"ResourceDetails\": {\n \"type\": \"facility\",\n \"hierarchyType\": \"ADMIN\",\n \"tenantId\": \"mz\",\n \"fileStoreId\": \"fd451260-67e8-4d57-a7bf-81734b0dccc7\",\n \"action\": \"validate\",\n \"campaignId\": \"22f77798-3645-44b3-98ee-cc5c0ff2888c\",\n \"additionalDetails\": {}\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1052,\n \"uuid\": \"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\n \"userName\": \"UATMZ\",\n \"name\": \"UATMZ\",\n \"mobileNumber\": \"8998988112\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS ADMIN\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1716899532287|en_IN\",\n \"plainAccessRequest\": {}\n }\n}" }, "url": { - "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=userWithBoundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=2c948509-4245-4df7-b46b-9cabd5cdb577", - "protocol": "https", + "raw": "http://localhost:8080/project-factory/v1/data/_generate?tenantId=mz&type=userWithBoundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=3b331cd6-c0e9-4fd4-9d15-9212ba51706c", + "protocol": "http", "host": [ - "unified-uat", - "digit", - "org" + "localhost" ], + "port": "8080", "path": [ "project-factory", "v1", @@ -328,7 +285,7 @@ }, { "key": "campaignId", - "value": "2c948509-4245-4df7-b46b-9cabd5cdb577" + "value": "3b331cd6-c0e9-4fd4-9d15-9212ba51706c" } ] } @@ -336,7 +293,7 @@ "response": [] }, { - "name": "data download", + "name": "download-generated Copy", "protocolProfileBehavior": { "disabledSystemHeaders": { "content-type": true @@ -454,13 +411,13 @@ "response": [] }, { - "name": "data create", + "name": "project-factory/v1/data/_create Copy", "request": { "method": "POST", "header": [ { "key": "authority", - "value": "unified-dev.digit.org" + "value": "unified-uat.digit.org" }, { "key": "accept", @@ -472,19 +429,19 @@ }, { "key": "content-type", - "value": "application/json" + "value": "application/json;charset=UTF-8" }, { "key": "cookie", - "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0; PGADMIN_LANGUAGE=en" }, { "key": "origin", - "value": "https://unified-dev.digit.org" + "value": "https://unified-uat.digit.org" }, { "key": "referer", - "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?id=3a567d66-9de5-4812-9441-240ae6ccb674&draft=true&fetchBoundary=true&key=9&preview=false" }, { "key": "sec-ch-ua", @@ -517,7 +474,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\":{\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"3dcb7be0-fa76-440f-959c-30c7839ca1d0\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1715753883629|en_MZ\",\n \"plainAccessRequest\": {}\n},\n \"ResourceDetails\": {\n \"type\": \"facility\",\n // \"type\": \"facility|user|boundary\",\n \"tenantId\": \"mz\",\n // empty facility\n // \"fileStoreId\": \"cf37fb7a-f07e-44da-9f11-c06841ffdd44\",\n // worng\n // \"fileStoreId\": \"823110ca-55a1-434b-83d4-138e9e262661\",\n // right\n // \"fileStoreId\":\"252e68d4-44f8-4088-814c-ba0046f7da0f\",\n // right user\n // \"fileStoreId\":\"589fc456-70ab-422f-9c9a-b92ea3304f54\",\n //rightt with 5000 rows\n // \"fileStoreId\": \"0b47f2b3-840a-40b5-af8d-2273b836fd79\",\n //rightt with 200 rows\n // \"fileStoreId\":\"078a35f3-6db9-497b-bed5-d58e0ae3800a\",\n \"fileStoreId\":\"ae72d4a2-1a3a-431c-b30a-699983cf9468\",\n \"action\": \"validate\",\n \"hierarchyType\": \"ADMIN\",\n \"additionalDetails\": {}\n }\n}" + "raw": "{\n \"ResourceDetails\": {\n \"type\": \"boundary\",\n \"hierarchyType\": \"TEST15\",\n \"tenantId\": \"mz\",\n \"fileStoreId\": \"{{fileId}}\",\n \"action\": \"create\",\n // \"campaignId\": \"56cd8661-9d4b-4946-80e9-d50bdcfcce60\",\n \"additionalDetails\": {}\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1052,\n \"uuid\": \"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\n \"userName\": \"UATMZ\",\n \"name\": \"UATMZ\",\n \"mobileNumber\": \"8998988112\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS ADMIN\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1717482930188|en_IN\",\n \"plainAccessRequest\": {}\n}\n}" }, "url": { "raw": "http://localhost:8080/project-factory/v1/data/_create", @@ -537,7 +494,90 @@ "response": [] }, { - "name": "data search", + "name": "project-factory/v1/project-type/search Copy", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-qa.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0" + }, + { + "key": "origin", + "value": "https://unified-qa.digit.org" + }, + { + "key": "referer", + "value": "https://unified-qa.digit.org/workbench-ui/employee/campaign/my-campaign" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1716986778045|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"tenantId\": \"mz\",\n \"ids\":[\"{{campaignId}}\"],\n // \"status\": [\n // \"creating\",\n // \"created\"\n // ],\n // \"createdBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n // \"campaignsIncludeDates\": true,\n // \"startDate\": 1716986778045,\n // \"endDate\": 1716986778045,\n // \"campaignName\":\"Performance Test Campaign Jun 17 id 00051\",\n \"pagination\": {\n \"sortBy\": \"createdTime\",\n \"sortOrder\": \"desc\",\n \"limit\": 10,\n \"offset\": 0\n }\n }\n}" + }, + "url": { + "raw": "http://localhost:8080/project-fctory/v1/project-type/search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "project-fctory", + "v1", + "project-type", + "search" + ] + } + }, + "response": [] + }, + { + "name": "project-factory/v1/project-type/search Copy 2", "request": { "method": "POST", "header": [ @@ -624,10 +664,142 @@ ] } }, - "response": [] + "response": [ + { + "name": "project-factory/v1/project-type/search Copy", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"4d18d41f-bf61-4a50-9382-c7728d57b076\",\n \"userInfo\": {\n \"id\": 947,\n \"uuid\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\",\n \"userName\": \"EMP44\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"HCM SYSTEM ADMINISTRATOR\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"SUPER USER\",\n \"code\": \"SUPERUSER\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"HRMS Admin\",\n \"code\": \"HRMS_ADMIN\",\n \"tenantId\": \"pg\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pg\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1709110250993|en_IN\",\n \"plainAccessRequest\": {}\n },\n \"SearchCriteria\": {\n \"id\": [\n \"fb34e006-0435-4565-acac-988a6992da54\"\n ],\n \"tenantId\": \"mz\",\n \"type\": \"facility\",\n \"status\": \"data-accepted\",\n \"action\": \"create\",\n \"createdBy\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\"\n }\n}" + }, + "url": { + "raw": "http://localhost:8095/project-factory/v1/data/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8095", + "path": [ + "project-factory", + "v1", + "data", + "_search" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "563" + }, + { + "key": "ETag", + "value": "W/\"233-jv57E1Q5Yt5KHhUp7M2vxbi5Abg\"" + }, + { + "key": "Date", + "value": "Tue, 02 Apr 2024 05:35:08 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"ResponseInfo\": {\n \"apiId\": \"egov-bff\",\n \"ver\": \"0.0.1\",\n \"ts\": 1712036108718,\n \"status\": \"successful\",\n \"desc\": \"new-response\"\n },\n \"ResourceDetails\": [\n {\n \"id\": \"fb34e006-0435-4565-acac-988a6992da54\",\n \"tenantId\": \"mz\",\n \"status\": \"data-accepted\",\n \"action\": \"create\",\n \"fileStoreId\": \"d5a6f652-37da-49a2-9284-e867b9e4de83\",\n \"processedFilestoreId\": \"5f1fcf05-e6d1-47e0-a96f-019a454cc7d2\",\n \"type\": \"facility\",\n \"createdBy\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\",\n \"lastModifiedBy\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\",\n \"createdTime\": 1710921693188,\n \"lastModifiedTime\": 1710921693188,\n \"additionalDetails\": {}\n }\n ]\n}" + } + ] }, { - "name": "campaign create", + "name": "/project-factory/v1/project-type/create Copy", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var response=pm.response.json();", + "pm.environment.set(\"campaignId\", response.CampaignDetails.id);", + "pm.environment.set(\"campaignNum\",response.CampaignDetails.campaignNumber)" + ], + "type": "text/javascript", + "packages": {} + } + } + ], "protocolProfileBehavior": { "disabledSystemHeaders": { "content-type": true @@ -699,15 +871,16 @@ ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"0cc530cb-aeb7-4735-a89b-ed5b0607518d\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1713593588138|en_MZ\",\n \"plainAccessRequest\": {}\n},\n \"CampaignDetails\": {\n // \"id\":\"f9f9b96a-d8aa-427b-a755-25bcc22ef60f\",\n \"hierarchyType\": \"ADMIN\",\n \"tenantId\": \"mz\",\n \"campaignName\": \"testName860\",\n \"action\": \"create\",\n // \"action\": \"create\",\n \"startDate\": 1765497222002,\n \"endDate\": 1767497225002,\n // \"projectId\":\"74c57591-13cc-4e21-97d3-2b6c87e7fc98\",\n \"boundaries\": [\n {\n \"code\": \"f5F6xAskA05\",\n \"type\": \"Provincia\",\n \"isRoot\": false\n },\n {\n \"code\": \"mz\",\n \"type\": \"Country\",\n \"isRoot\": true,\n \"includeAllChildren\": true\n }\n ],\n \"resources\": [\n {\n \"filestoreId\": \"252e68d4-44f8-4088-814c-ba0046f7da0f\",\n \"type\": \"facility\",\n \"filename\": \"hkjsss.xlsx\"\n },\n {\n \"filestoreId\":\"49280d90-31f2-4911-8d1e-0482cc6bf70c\",\n \"type\": \"user\",\n \"filename\": \"hkjsss.xlsx\"\n }\n // {\n // \"filestoreId\": \"d96c0248-dcfd-414c-8f8c-635dad0a89f1\",\n // \"type\": \"boundary\",\n // \"filename\": \"s.xlsx\"\n // }\n ],\n \"projectType\": \"LLIN-mz\",\n \"deliveryRules\": [\n {\n \"startDate\": 1666497225000,\n \"endDate\": 1666497225000,\n \"cycleNumber\": 0,\n \"deliveryNumber\": 0,\n \"deliveryRuleNumber\": 0,\n \"products\": [\n \"string\"\n ],\n \"conditions\": [\n {\n \"attribute\": \"string\",\n \"operator\": \"string\",\n \"value\": 0\n }\n ]\n }\n // {\n // \"startDate\": 1667497225001,\n // \"endDate\": 1668897225001,\n // \"cycleNumber\": 0,\n // \"deliveryNumber\": 0,\n // \"deliveryRuleNumber\": 0,\n // \"products\": [\n // \"string\"\n // ],\n // \"conditions\": [\n // {\n // \"attribute\": \"string\",\n // \"operator\": \"string\",\n // \"value\": 0\n // }\n // ]\n // }\n ],\n \"additionalDetails\": {\n \"beneficiaryType\": \"HOUSEHOLD\"\n }\n }\n}" + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1713593588138|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n // \"id\": \"992f8c27-7dde-43f8-9dad-e6ec9d821d39\",\n \"tenantId\": \"mz\",\n // \"status\": \"created\",\n \"action\": \"draft\",\n // \"campaignNumber\": \"CMP-2024-07-30-001374\",\n \"campaignName\": \"jul31_3\",\n \"projectType\": \"LLIN-mz\",\n \"hierarchyType\": \"Health\",\n \"boundaryCode\": \"HEALTH_MO\",\n // \"projectId\": \"baeadf90-ded8-47eb-a02a-c4c9c4527321\",\n \"startDate\": 1722450600000,\n \"endDate\": 1725560999000,\n \"additionalDetails\": {\n \"key\": 10,\n \"beneficiaryType\": \"HOUSEHOLD\"\n },\n \"resources\": [\n {\n \"type\": \"facility\",\n \"filename\": \"Facility Template (56).xlsx\",\n \"resourceId\": \"31a528c6-1345-4587-ad21-7bafcbe3b28f\",\n \"filestoreId\": \"6aebec94-463d-4f81-bb13-5c42ac848c25\",\n \"createResourceId\": \"628b0382-4964-441a-a687-9391b92fa5e5\"\n },\n {\n \"type\": \"boundaryWithTarget\",\n \"filename\": \"Target Template (84).xlsx\",\n \"resourceId\": \"7244300a-dd01-49ca-a39f-27845e84f28c\",\n \"filestoreId\": \"dc3c52ea-96b0-49b4-b38e-6360f09b98e3\"\n },\n {\n \"type\": \"user\",\n \"filename\": \"User Template (30).xlsx\",\n \"resourceId\": \"3fa115c9-a394-48a9-8c53-c9929b0abd0e\",\n \"filestoreId\": \"a0254f2e-1ed0-4255-b471-9a912230eb96\",\n \"createResourceId\": \"ebeaf8e1-e185-4b64-98f1-43b9eb8cc095\"\n }\n ],\n \"boundaries\": [\n {\n \"code\": \"HEALTH_MO\",\n \"type\": \"Country\",\n \"isRoot\": true,\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_NAMPULA\",\n \"type\": \"Province\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_02_CHITIMA-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_02_01_NSADZO\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_01_04_NIHESSIUE\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_03_CHITEEIMA\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_02_CHIFUNDE-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_01_MUALDZI\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n }\n ],\n \"deliveryRules\": [\n {\n \"endDate\": 1723573799000,\n \"products\": [\n {\n \"name\": \"SP 500mg\",\n \"count\": 1,\n \"value\": \"PVAR-2024-03-15-000043\"\n }\n ],\n \"startDate\": 1722537000000,\n \"conditions\": [\n {\n \"value\": 3,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_INDIVIDUAL_LABEL\"\n },\n {\n \"value\": 1.8,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_HOUSEHOLD_LABEL\"\n }\n ],\n \"cycleNumber\": 1,\n \"deliveryNumber\": 1,\n \"deliveryRuleNumber\": 1\n }\n ],\n \"auditDetails\": {\n \"createdBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"lastModifiedBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"createdTime\": 1722324752043,\n \"lastModifiedTime\": 1722324899659\n }\n }\n}" }, "url": { - "raw": "http://localhost:8080/project-factory/v1/project-type/create", - "protocol": "http", + "raw": "https://unified-dev.digit.org/project-factory/v1/project-type/create", + "protocol": "https", "host": [ - "localhost" + "unified-dev", + "digit", + "org" ], - "port": "8080", "path": [ "project-factory", "v1", @@ -719,7 +892,7 @@ "response": [] }, { - "name": "update campaign", + "name": "/project-factory/v1/project-type/update Copy", "protocolProfileBehavior": { "disabledSystemHeaders": { "content-type": true @@ -792,13 +965,13 @@ ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"44cb5589-8dc2-4182-b5a4-afdb692ce831\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"id\": \"f9ea7046-75f2-4ac3-837d-caf14fdcdcca\",\n \"tenantId\": \"mz\",\n \"status\": \"drafted\",\n \"action\": \"draft\",\n \"campaignNumber\": \"CMP-2024-05-02-000855\",\n \"campaignName\": \"weartux\",\n \"projectType\": \"MR-DN\",\n \"hierarchyType\": \"ADMIN\",\n \"boundaryCode\": \"\",\n \"projectId\": null,\n \"startDate\": 0,\n \"endDate\": 0,\n \"createdBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"lastModifiedBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"createdTime\": 1714654527543,\n \"lastModifiedTime\": 1714654527544,\n \"additionalDetails\": {\n \"key\": 2,\n \"beneficiaryType\": \"INDIVIDUAL\"\n },\n \"campaignDetails\": {\n \"resources\": []\n }\n }\n}\n// \"boundaries\": [\n// {\n// \"code\": \"f5F6xAskA05\",\n// \"type\": \"Provincia\",\n// \"isRoot\": false\n// },\n// {\n// \"code\": \"mz\",\n// \"type\": \"Country\",\n// \"isRoot\": true,\n// \"includeAllChildren\": true\n// }\n// ]," + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"44cb5589-8dc2-4182-b5a4-afdb692ce831\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"id\": \"{{campaignId}}\",\n \"tenantId\": \"mz\",\n \"status\": \"drafted\",\n \"action\": \"create\",\n \"campaignNumber\": \"{{campaignNum}}\",\n \"campaignName\": \"{{campaignName}}\",\n \"projectType\": \"LLIN-mz\",\n \"hierarchyType\": \"Health\",\n \"boundaryCode\": \"HEALTH_MO\",\n // \"projectId\": \"baeadf90-ded8-47eb-a02a-c4c9c4527321\",\n \"startDate\": 1722450600000,\n \"endDate\": 1725560999000,\n \"additionalDetails\": {\n \"key\": 10,\n \"beneficiaryType\": \"HOUSEHOLD\"\n },\n \"resources\": [\n {\n \"type\": \"facility\",\n \"filename\": \"Facility Template (56).xlsx\",\n \"resourceId\": \"31a528c6-1345-4587-ad21-7bafcbe3b28f\",\n \"filestoreId\": \"6aebec94-463d-4f81-bb13-5c42ac848c25\",\n \"createResourceId\": \"628b0382-4964-441a-a687-9391b92fa5e5\"\n },\n {\n \"type\": \"boundaryWithTarget\",\n \"filename\": \"Target Template (84).xlsx\",\n \"resourceId\": \"7244300a-dd01-49ca-a39f-27845e84f28c\",\n \"filestoreId\": \"dc3c52ea-96b0-49b4-b38e-6360f09b98e3\"\n },\n {\n \"type\": \"user\",\n \"filename\": \"User Template (30).xlsx\",\n \"resourceId\": \"3fa115c9-a394-48a9-8c53-c9929b0abd0e\",\n \"filestoreId\": \"a0254f2e-1ed0-4255-b471-9a912230eb96\",\n \"createResourceId\": \"ebeaf8e1-e185-4b64-98f1-43b9eb8cc095\"\n }\n ],\n \"boundaries\": [\n {\n \"code\": \"HEALTH_MO\",\n \"type\": \"Country\",\n \"isRoot\": true,\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_NAMPULA\",\n \"type\": \"Province\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_02_CHITIMA-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_02_01_NSADZO\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_01_04_NIHESSIUE\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_03_CHITEEIMA\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_02_CHIFUNDE-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_01_MUALDZI\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n }\n ],\n \"deliveryRules\": [\n {\n \"endDate\": 1723573799000,\n \"products\": [\n {\n \"name\": \"SP 500mg\",\n \"count\": 1,\n \"value\": \"PVAR-2024-03-15-000043\"\n }\n ],\n \"startDate\": 1722537000000,\n \"conditions\": [\n {\n \"value\": 3,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_INDIVIDUAL_LABEL\"\n },\n {\n \"value\": 1.8,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_HOUSEHOLD_LABEL\"\n }\n ],\n \"cycleNumber\": 1,\n \"deliveryNumber\": 1,\n \"deliveryRuleNumber\": 1\n }\n ],\n \"auditDetails\": {\n \"createdBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"lastModifiedBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"createdTime\": 1722324752043,\n \"lastModifiedTime\": 1722324899659\n }\n }\n}" }, "url": { - "raw": "https://unified-qa.digit.org/project-factory/v1/project-type/update", + "raw": "https://unified-dev.digit.org/project-factory/v1/project-type/update", "protocol": "https", "host": [ - "unified-qa", + "unified-dev", "digit", "org" ], @@ -813,7 +986,12 @@ "response": [] }, { - "name": "campaign search", + "name": "getProcessTracks Copy", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, "request": { "method": "POST", "header": [ @@ -872,28 +1050,39 @@ { "key": "user-agent", "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json" } ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"b2985fc2-9980-4fba-adcf-3248e3a66490\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"ids\": [\n \"7cfc93f2-9c4c-4415-9417-e61d2203bdd8\"\n ],\n \"tenantId\": \"mz\",\n // \"startDate\": 1665497224000,\n // \"endDate\": 1665929226005,\n // \"projectType\": \"default1\",\n // \"campaignName\": \"test1Name803\",\n // \"status\": \"started\",\n // \"createdBy\": \"string\",\n // \"campaignNumber\": \"string\",\n \"pagination\": {\n \"sortBy\": \"createdTime\",\n \"sortOrder\": \"desc\",\n \"limit\": 15,\n \"offset\": 0\n }\n // \"createdTime\":1665929226005\n }\n}" + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1713593588138|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" }, "url": { - "raw": "http://localhost:8080/project-factory/v1/project-type/search", - "protocol": "http", + "raw": "https://unified-dev.digit.org/project-factory/v1/project-type/getProcessTrack?campaignId=eeded5f1-e779-454f-9cc7-2b20ba4839e0", + "protocol": "https", "host": [ - "localhost" + "unified-dev", + "digit", + "org" ], - "port": "8080", "path": [ "project-factory", "v1", "project-type", - "search" + "getProcessTrack" + ], + "query": [ + { + "key": "campaignId", + "value": "eeded5f1-e779-454f-9cc7-2b20ba4839e0" + } ] } }, "response": [] } ] -} +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/api/campaignApis.ts b/health-services/project-factory/src/server/api/campaignApis.ts index f0a5a231965..c063f1e653d 100644 --- a/health-services/project-factory/src/server/api/campaignApis.ts +++ b/health-services/project-factory/src/server/api/campaignApis.ts @@ -3,15 +3,17 @@ import { v4 as uuidv4 } from 'uuid'; import { httpRequest } from "../utils/request"; import { getFormattedStringForDebug, logger } from "../utils/logger"; import createAndSearch from '../config/createAndSearch'; -import { getDataFromSheet, generateActivityMessage, throwError, translateSchema, replicateRequest } from "../utils/genericUtils"; +import { getDataFromSheet, generateActivityMessage, throwError, translateSchema, replicateRequest, appendProjectTypeToCapacity } from "../utils/genericUtils"; import { immediateValidationForTargetSheet, validateSheetData, validateTargetSheetData } from '../validators/campaignValidators'; import { callMdmsTypeSchema, getCampaignNumber } from "./genericApis"; -import { boundaryBulkUpload, convertToTypeData, generateHierarchy, generateProcessedFileAndPersist, getLocalizedName, reorderBoundariesOfDataAndValidate } from "../utils/campaignUtils"; +import { boundaryBulkUpload, convertToTypeData, generateHierarchy, generateProcessedFileAndPersist, getBoundaryOnWhichWeSplit, getLocalizedName, reorderBoundariesOfDataAndValidate, checkIfSourceIsMicroplan } from "../utils/campaignUtils"; const _ = require('lodash'); -import { produceModifiedMessages } from "../kafka/Listener"; +import { produceModifiedMessages } from "../kafka/Producer"; import { createDataService } from "../service/dataManageService"; import { searchProjectTypeCampaignService } from "../service/campaignManageService"; import { getExcelWorkbookFromFileURL } from "../utils/excelUtils"; +import { processTrackStatuses, processTrackTypes } from "../config/constants"; +import { persistTrack } from "../utils/processTrackUtils"; @@ -258,8 +260,18 @@ async function getUuidsError(request: any, response: any, mobileNumberRowNumberM errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have username` }) count++; } + else if (!user?.userDetails?.password) { + logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have password`) + errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have password` }) + count++; + } + else if (!user?.userUuid) { + logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid`) + errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid` }) + count++; + } else { - request.body.mobileNumberUuidsMapping[user?.mobileNumber] = { userUuid: user?.id, code: user?.userDetails?.username, rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber] } + request.body.mobileNumberUuidsMapping[user?.mobileNumber] = { userUuid: user?.id, code: user?.userDetails?.username, rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], password: user?.userDetails?.password, userServiceUuid: user?.userUuid } } } if (count > 0) { @@ -518,11 +530,12 @@ async function processValidate(request: any, localizationMap?: { [key: string]: const createAndSearchConfig = createAndSearch[type] const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, null, localizationMap) if (type == 'boundaryWithTarget') { + let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request); + differentTabsBasedOnLevel = getLocalizedName(`${request?.body?.ResourceDetails?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), localizationMap); logger.info("target sheet format validation started"); - // added await to ensure validations complete before proceeding, preventing premature errors. - await immediateValidationForTargetSheet(dataFromSheet, localizationMap); + await immediateValidationForTargetSheet(request, dataFromSheet, differentTabsBasedOnLevel, localizationMap); logger.info("target sheet format validation completed and starts with data validation"); - validateTargetSheetData(dataFromSheet, request, createAndSearchConfig?.boundaryValidation, localizationMap); + validateTargetSheetData(dataFromSheet, request, createAndSearchConfig?.boundaryValidation, differentTabsBasedOnLevel, localizationMap); } else { @@ -693,7 +706,8 @@ async function enrichAlreadyExsistingUser(request: any) { employee.uuid = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].userUuid; employee.code = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].code; employee.user.userName = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].code; - employee.user.password = config.user.userDefaultPassword; + employee.user.password = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].password; + employee.user.userServiceUuid = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].userServiceUuid; } } } @@ -716,7 +730,7 @@ async function performAndSaveResourceActivity(request: any, createAndSearchConfi } _.set(newRequestBody, createAndSearchConfig?.createBulkDetails?.createPath, chunkData); creationTime = Date.now(); - if (type == "facility") { + if (type == "facility" || type == "facilityMicroplan") { await handeFacilityProcess(request, createAndSearchConfig, params, activities, newRequestBody); } else if (type == "user") { @@ -774,16 +788,27 @@ async function handleResouceDetailsError(request: any, error: any) { if (request?.body?.ResourceDetails?.action == "create") { persistMessage.ResourceDetails.additionalDetails = { error: stringifiedError } } - produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); + await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); } - if (request?.body?.Activities && Array.isArray(request?.body?.Activities && request?.body?.Activities.length > 0)) { + if (request?.body?.Activities && Array.isArray(request?.body?.Activities) && request?.body?.Activities.length > 0) { logger.info("Waiting for 2 seconds"); await new Promise(resolve => setTimeout(resolve, 2000)); - produceModifiedMessages(request?.body, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + const activityObject = request?.body?.Activities; + await produceModifiedMessages(activityObject, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + } +} + +async function persistCreationProcess(request: any, status: any) { + if (request?.body?.ResourceDetails?.type == "facility") { + await persistTrack(request?.body?.ResourceDetails?.campaignId, processTrackTypes.facilityCreation, status); + } + else if (request?.body?.ResourceDetails?.type == "user") { + await persistTrack(request?.body?.ResourceDetails?.campaignId, processTrackTypes.staffCreation, status); } } async function processAfterValidation(dataFromSheet: any, createAndSearchConfig: any, request: any, localizationMap?: { [key: string]: string }) { + await persistCreationProcess(request, processTrackStatuses.inprogress) try { const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) request.body.dataToCreate = typeData.createData; @@ -801,8 +826,10 @@ async function processAfterValidation(dataFromSheet: any, createAndSearchConfig: } } catch (error: any) { console.log(error) + await persistCreationProcess(request, processTrackStatuses.failed) await handleResouceDetailsError(request, error) } + await persistCreationProcess(request, processTrackStatuses.completed) } /** @@ -817,14 +844,39 @@ async function processCreate(request: any, localizationMap?: any) { boundaryBulkUpload(request, localizationMap); } else { - const createAndSearchConfig = createAndSearch[type] + // console.log(`Source is MICROPLAN -->`, source); + let createAndSearchConfig: any; + createAndSearchConfig = createAndSearch[type]; + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; + if (checkIfSourceIsMicroplan(request?.body?.ResourceDetails)) { + logger.info(`Data create Source is MICROPLAN`); + if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { + createAndSearchConfig.parseArrayConfig.parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic.map( + (item: any) => { + if (item.sheetColumn === "E") { + item.sheetColumnName += `_${campaignType}`; + } + return item; + } + ); + } + } + const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, undefined, localizationMap) let schema: any; + if (type == "facility") { logger.info("Fetching schema to validate the created data for type: " + type); const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); schema = mdmsResponse } + else if (type == "facilityMicroplan") { + const mdmsResponse = await callMdmsTypeSchema(request, tenantId, "facility", "microplan"); + schema = mdmsResponse + logger.info("Appending project type to capacity for microplan " + campaignType); + schema = await appendProjectTypeToCapacity(schema, campaignType); + } else if (type == "user") { logger.info("Fetching schema to validate the created data for type: " + type); const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); @@ -843,33 +895,41 @@ async function processCreate(request: any, localizationMap?: any) { * @param request The HTTP request object. */ async function createProjectCampaignResourcData(request: any) { - // Create resources for a project campaign - if (request?.body?.CampaignDetails?.action == "create" && request?.body?.CampaignDetails?.resources) { - for (const resource of request?.body?.CampaignDetails?.resources) { - if (resource.type != "boundaryWithTarget") { - const resourceDetails = { - type: resource.type, - fileStoreId: resource.filestoreId, - tenantId: request?.body?.CampaignDetails?.tenantId, - action: "create", - hierarchyType: request?.body?.CampaignDetails?.hierarchyType, - additionalDetails: {}, - campaignId: request?.body?.CampaignDetails?.id - }; - logger.info(`Creating the resources for type ${resource.type}`) - logger.debug("resourceDetails " + getFormattedStringForDebug(resourceDetails)) - const createRequestBody = { - RequestInfo: request.body.RequestInfo, - ResourceDetails: resourceDetails - } - const req = replicateRequest(request, createRequestBody) - const res: any = await createDataService(req) - if (res?.id) { - resource.createResourceId = res?.id + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.inprogress); + try { + // Create resources for a project campaign + if (request?.body?.CampaignDetails?.action == "create" && request?.body?.CampaignDetails?.resources) { + for (const resource of request?.body?.CampaignDetails?.resources) { + if (resource.type != "boundaryWithTarget") { + const resourceDetails = { + type: resource.type, + fileStoreId: resource.filestoreId, + tenantId: request?.body?.CampaignDetails?.tenantId, + action: "create", + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + additionalDetails: {}, + campaignId: request?.body?.CampaignDetails?.id + }; + logger.info(`Creating the resources for type ${resource.type}`) + logger.debug("resourceDetails " + getFormattedStringForDebug(resourceDetails)) + const createRequestBody = { + RequestInfo: request.body.RequestInfo, + ResourceDetails: resourceDetails + } + const req = replicateRequest(request, createRequestBody) + const res: any = await createDataService(req) + if (res?.id) { + resource.createResourceId = res?.id + } } } } + } catch (error: any) { + console.log(error) + await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) } + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.completed); } async function confirmProjectParentCreation(request: any, projectId: any) { diff --git a/health-services/project-factory/src/server/api/genericApis.ts b/health-services/project-factory/src/server/api/genericApis.ts index 3325efc9d73..c7fa9ced8e0 100644 --- a/health-services/project-factory/src/server/api/genericApis.ts +++ b/health-services/project-factory/src/server/api/genericApis.ts @@ -6,10 +6,9 @@ import { getFormattedStringForDebug, logger } from "../utils/logger"; // Import import { correctParentValues, findMapValue, generateActivityMessage, getBoundaryRelationshipData, getDataSheetReady, getLocalizedHeaders, sortCampaignDetails, throwError } from "../utils/genericUtils"; // Import utility functions import { extractCodesFromBoundaryRelationshipResponse, generateFilteredBoundaryData, getConfigurableColumnHeadersBasedOnCampaignType, getFiltersFromCampaignSearchResponse, getLocalizedName } from '../utils/campaignUtils'; // Import utility functions import { getCampaignSearchResponse, getHierarchy } from './campaignApis'; -import { validateMappingId } from '../utils/campaignMappingUtils'; -import { campaignStatuses } from '../config/constants'; const _ = require('lodash'); // Import lodash library import { getExcelWorkbookFromFileURL } from "../utils/excelUtils"; +import { processMapping } from "../utils/campaignMappingUtils"; //Function to get Workbook with different tabs (for type target) @@ -38,9 +37,9 @@ const getTargetWorkbook = async (fileUrl: string, localizationMap?: any) => { function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheetName = "sheet1") { const jsonData: any[] = []; - const headers = sheetData[1]; // Extract the headers from the first row + const headers = sheetData[0]; // Extract the headers from the first row - for (let i = 2; i < sheetData.length; i++) { + for (let i = 1; i < sheetData.length; i++) { const rowData: any = {}; const row = sheetData[i]; if (row) { @@ -52,7 +51,7 @@ function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheet } } if (Object.keys(rowData).length > 0) { - if (getRow) rowData["!row#number!"] = i; + if (getRow) rowData["!row#number!"] = i + 1; if (getSheetName) rowData["!sheet#name!"] = sheetName; jsonData.push(rowData); } @@ -62,11 +61,7 @@ function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheet } function validateFirstRowColumn(createAndSearchConfig: any, worksheet: any, localizationMap: any) { - if ( - createAndSearchConfig && - createAndSearchConfig.parseArrayConfig && - createAndSearchConfig.parseArrayConfig.parseLogic - ) { + if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { const parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic; // Iterate over each column configuration for (const columnConfig of parseLogic) { @@ -91,6 +86,25 @@ function validateFirstRowColumn(createAndSearchConfig: any, worksheet: any, loca } } +function getSheetDataFromWorksheet(worksheet: any) { + var sheetData: any[][] = []; + + worksheet.eachRow({ includeEmpty: true }, (row: any, rowNumber: any) => { + const rowData: any[] = []; + + row.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { + const cellValue = getRawCellValue(cell); + rowData[colNumber - 1] = cellValue; // Store cell value (0-based index) + }); + + // Push non-empty row only + if (rowData.some(value => value !== null && value !== undefined)) { + sheetData[rowNumber - 1] = rowData; // Store row data (0-based index) + } + }); + return sheetData; +} + // Function to retrieve data from a specific sheet in an Excel file const getSheetData = async ( fileUrl: string, @@ -99,19 +113,42 @@ const getSheetData = async ( createAndSearchConfig?: any, localizationMap?: { [key: string]: string } ) => { - // Retrieve workbook using the getTargetWorkbook function + // Retrieve workbook using the getExcelWorkbookFromFileURL function const localizedSheetName = getLocalizedName(sheetName, localizationMap); const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, localizedSheetName); const worksheet: any = workbook.getWorksheet(localizedSheetName); - // If parsing array configuration is provided, validate first row of each column validateFirstRowColumn(createAndSearchConfig, worksheet, localizationMap); - const sheetData = worksheet.getSheetValues({ includeEmpty: true }); + // Collect sheet data by iterating through rows and cells + const sheetData = getSheetDataFromWorksheet(worksheet); const jsonData = getJsonData(sheetData, getRow); return jsonData; +}; + +// Helper function to extract raw cell value +function getRawCellValue(cell: any) { + if (cell.value && typeof cell.value === 'object') { + if ('richText' in cell.value) { + // Handle rich text + return cell.value.richText.map((rt: any) => rt.text).join(''); + } else if ('formula' in cell.value) { + // Get the result of the formula + return cell.value.result; + } else if ('error' in cell.value) { + // Get the error value + return cell.value.error; + } else if (cell.value instanceof Date) { + // Handle date values + return cell.value.toISOString(); + } else { + // Return as-is for other object types + return cell.value; + } + } + return cell.value; // Return raw value for plain strings, numbers, etc. } const getTargetSheetData = async ( @@ -131,7 +168,7 @@ const getTargetSheetData = async ( for (const sheetName of localizedSheetNames) { const worksheet = workbook.getWorksheet(sheetName); - const sheetData = worksheet.getSheetValues({ includeEmpty: true }); + const sheetData = getSheetDataFromWorksheet(worksheet); workbookData[sheetName] = getJsonData(sheetData, getRow, getSheetName, sheetName); } return workbookData; @@ -155,10 +192,10 @@ const getTargetSheetDataAfterCode = async ( for (const sheetName of localizedSheetNames) { const worksheet = workbook.getWorksheet(sheetName); - const sheetData = worksheet.getSheetValues({ includeEmpty: true }); + const sheetData = getSheetDataFromWorksheet(worksheet); // Find the target column index where the first row value matches codeColumnName - const firstRow = sheetData[1]; + const firstRow = sheetData[0]; let targetColumnIndex = -1; for (let colIndex = 1; colIndex < firstRow.length; colIndex++) { if (firstRow[colIndex] === codeColumnName) { @@ -545,26 +582,31 @@ async function getAutoGeneratedBoundaryCodes(boundaryList: any, childParentMap: const column = columnsData[i]; for (const element of column) { if (!findMapValue(elementCodesMap, element)) { - const parentCode = findMapValue(childParentMap, element) - if (parentCode !== undefined && parentCode !== null) { - countMap.set(parentCode, (findMapValue(countMap, parentCode) || 0) + 1); - let code; - const grandParentCode = findMapValue(childParentMap, parentCode); - if (grandParentCode != null && grandParentCode != undefined) { - const parentBoundaryCode = findMapValue(elementCodesMap, parentCode) - const lastUnderscoreIndex = parentBoundaryCode.lastIndexOf('_'); - const parentBoundaryCodeTrimmed = lastUnderscoreIndex !== -1 ? parentBoundaryCode.substring(0, lastUnderscoreIndex) : parentBoundaryCode; - code = generateElementCode(countMap.get(parentCode), parentBoundaryCodeTrimmed, element.value); - } else { - code = generateElementCode(countMap.get(parentCode), findMapValue(elementCodesMap, parentCode), element.value); - } + const parentElement = findMapValue(childParentMap, element); + if (parentElement !== undefined && parentElement !== null) { + const parentBoundaryCode = findMapValue(elementCodesMap, parentElement); + const currentCount = (findMapValue(countMap, parentElement) || 0) + 1; + countMap.set(parentElement, currentCount); + + const code = generateElementCode( + currentCount, + parentElement, + parentBoundaryCode, + element.value, + config.excludeBoundaryNameAtLastFromBoundaryCodes, + childParentMap, + elementCodesMap + ); + elementCodesMap.set(element, code); // Store the code of the element in the map } else { // Generate default code if parent code is not found - elementCodesMap.set(element, (request?.body?.ResourceDetails?.hierarchyType + "_").toUpperCase() + element.value.toString().substring(0, 2).toUpperCase()); + const prefix = config?.excludeHierarchyTypeFromBoundaryCodes + ? element.value.toString().substring(0, 2).toUpperCase() + : `${(request?.body?.ResourceDetails?.hierarchyType + "_").toUpperCase()}${element.value.toString().substring(0, 2).toUpperCase()}`; + + elementCodesMap.set(element, prefix); } - } else { - continue; } } } @@ -574,21 +616,33 @@ async function getAutoGeneratedBoundaryCodes(boundaryList: any, childParentMap: /** * Function to generate an element code based on sequence, parent code, and element. * @param sequence Sequence number - * @param parentCode Parent code + * @param parentElement Parent element + * @param parentBoundaryCode Parent boundary code * @param element Element + * @param excludeBoundaryNameAtLastFromBoundaryCodes Whether to exclude boundary name at last + * @param childParentMap Map of child to parent elements + * @param elementCodesMap Map of elements to their codes * @returns Generated element code */ -function generateElementCode(sequence: any, parentCode: any, element: any) { +function generateElementCode(sequence: any, parentElement: any, parentBoundaryCode: any, element: any, excludeBoundaryNameAtLastFromBoundaryCodes?: any, childParentMap?: any, elementCodesMap?: any) { // Pad single-digit numbers with leading zero - let paddedSequence = sequence.toString().padStart(2, "0"); - const code = parentCode.toUpperCase() + - "_" + - paddedSequence + - "_" + - element.toUpperCase(); - return ( - code.trim() - ); + const paddedSequence = sequence.toString().padStart(2, "0"); + let code; + + if (excludeBoundaryNameAtLastFromBoundaryCodes) { + code = `${parentBoundaryCode.toUpperCase()}_${paddedSequence}`; + } else { + const grandParentElement = findMapValue(childParentMap, parentElement); + if (grandParentElement != null && grandParentElement != undefined) { + const lastUnderscoreIndex = parentBoundaryCode ? parentBoundaryCode.lastIndexOf('_') : -1; + const parentBoundaryCodeTrimmed = lastUnderscoreIndex !== -1 ? parentBoundaryCode.substring(0, lastUnderscoreIndex) : parentBoundaryCode; + code = `${parentBoundaryCodeTrimmed.toUpperCase()}_${paddedSequence}_${element.toString().toUpperCase()}`; + } else { + code = `${parentBoundaryCode.toUpperCase()}_${paddedSequence}_${element.toString().toUpperCase()}`; + } + } + + return code.trim(); } /** @@ -637,21 +691,35 @@ async function getBoundarySheetData( headers ); } else { - // logger.info("boundaryData for sheet " + JSON.stringify(boundaryData)) - const responseFromCampaignSearch = - await getCampaignSearchResponse(request); - const FiltersFromCampaignId = getFiltersFromCampaignSearchResponse(responseFromCampaignSearch) - if (FiltersFromCampaignId?.Filters != null) { + let Filters: any = {}; + if (request?.body?.Filters && request?.body?.Filters.boundaries && Array.isArray(request?.body?.Filters.boundaries) && request?.body?.Filters.boundaries.length > 0) { + Filters = { + Filters: { + boundaries: request.body.Filters.boundaries.map((boundary: any) => ({ + ...boundary, + boundaryType: boundary.type // Adding boundaryType field + })) + } + }; + } + else { + // logger.info("boundaryData for sheet " + JSON.stringify(boundaryData)) + const responseFromCampaignSearch = + await getCampaignSearchResponse(request); + Filters = getFiltersFromCampaignSearchResponse(responseFromCampaignSearch) + } + if (Filters?.Filters && Filters.Filters.boundaries && Array.isArray(Filters.Filters.boundaries) && Filters.Filters.boundaries.length > 0) { const filteredBoundaryData = await generateFilteredBoundaryData( request, - FiltersFromCampaignId + Filters ); return await getDataSheetReady( filteredBoundaryData, request, localizationMap ); - } else { + } + else { return await getDataSheetReady(boundaryData, request, localizationMap); } } @@ -671,8 +739,7 @@ async function createStaff(resouceBody: any) { undefined, undefined, undefined, - false, - true + false ); logger.info("Project Staff mapping created"); logger.debug( @@ -700,8 +767,7 @@ async function createProjectResource(resouceBody: any) { undefined, undefined, undefined, - false, - true + false ); logger.debug("Project Resource Created"); logger.debug( @@ -729,8 +795,7 @@ async function createProjectFacility(resouceBody: any) { undefined, undefined, undefined, - false, - true + false ); logger.info("Project Facility Created"); logger.debug( @@ -792,32 +857,31 @@ const createProjectFacilityHelper = (resourceId: any, projectId: any, resouceBod * @param resouceBody The resource body. */ async function createRelatedEntity( - resources: any, - tenantId: any, - projectId: any, - startDate: any, - endDate: any, - resouceBody: any + createRelatedEntityArray: any[], + CampaignDetails: any, + requestBody: any ) { - // Array to hold all promises - const promises = []; - - // Create related entities - for (const resource of resources) { - const type = resource?.type; - for (const resourceId of resource?.resourceIds) { - logger.info(`creating project ${type} mapping for project : ${projectId} and resourceId ${resourceId}`); - if (type === "staff") { - promises.push(createStaffHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)); - } else if (type === "resource") { - promises.push(createProjectResourceHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)); - } else if (type === "facility") { - promises.push(createProjectFacilityHelper(resourceId, projectId, resouceBody, tenantId)); + const mappingArray = [] + for (const entity of createRelatedEntityArray) { + const { tenantId, projectId, startDate, endDate, resouceBody, campaignId, resources } = entity + for (const resource of resources) { + const type = resource?.type; + const mappingObject: any = { + type, + tenantId, + resource, + projectId, + startDate, + endDate, + resouceBody, + campaignId, + CampaignDetails } + mappingArray.push(mappingObject) } } - // Wait for all promises to complete - await Promise.all(promises); + const mappingObject: any = { mappingArray: mappingArray, CampaignDetails: CampaignDetails, RequestInfo: requestBody?.RequestInfo } + await processMapping(mappingObject) } @@ -827,32 +891,34 @@ async function createRelatedEntity( */ async function createRelatedResouce(requestBody: any) { const id = requestBody?.Campaign?.id; - const campaignDetails = await validateMappingId(requestBody, id); - if (campaignDetails?.status == campaignStatuses.inprogress) { - logger.info("Campaign Already In Progress and Mapped"); - } else { - sortCampaignDetails(requestBody?.Campaign?.CampaignDetails); - correctParentValues(requestBody?.Campaign?.CampaignDetails); - // Create related resources - const { tenantId } = requestBody?.Campaign; - - for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { - const resouceBody: any = { - RequestInfo: requestBody.RequestInfo, - }; - var { projectId, startDate, endDate, resources } = campaignDetails; - startDate = parseInt(startDate); - endDate = parseInt(endDate); - await createRelatedEntity( - resources, - tenantId, - projectId, - startDate, - endDate, - resouceBody - ); - } + sortCampaignDetails(requestBody?.Campaign?.CampaignDetails); + correctParentValues(requestBody?.Campaign?.CampaignDetails); + // Create related resources + const { tenantId } = requestBody?.Campaign; + const createRelatedEntityArray = []; + for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { + const resouceBody: any = { + RequestInfo: requestBody.RequestInfo, + }; + var { projectId, startDate, endDate, resources } = campaignDetails; + campaignDetails.id = id; + startDate = parseInt(startDate); + endDate = parseInt(endDate); + createRelatedEntityArray.push({ + resources, + tenantId, + projectId, + startDate, + endDate, + resouceBody, + campaignId: id, + }); } + await createRelatedEntity( + createRelatedEntityArray, + requestBody?.CampaignDetails, + requestBody + ); } /** @@ -1006,7 +1072,7 @@ async function createBoundaryRelationship(request: any, boundaryMap: Map<{ key: logger.info(`Boundary relationship created for boundaryType :: ${boundaryType} & boundaryCode :: ${boundaryCode} `); const newRequestBody = JSON.parse(JSON.stringify(request.body)); - activityMessage.push(await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, response, request?.body?.ResourceDetails?.type, url, response?.statusCode)); + activityMessage.push(await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, response, request?.body?.ResourceDetails?.type, `${config.host.boundaryHost}${config.paths.boundaryRelationshipCreate}`, response?.statusCode)); } catch (error) { // Log the error and rethrow to be caught by the outer try...catch block logger.error(`Error creating boundary relationship for boundaryType :: ${boundaryType} & boundaryCode :: ${boundaryCode} :: `, error); @@ -1187,5 +1253,8 @@ export { getTargetSheetDataAfterCode, callMdmsData, getMDMSV1Data, - callMdmsTypeSchema -} + callMdmsTypeSchema, + getSheetDataFromWorksheet, + createStaffHelper, + createProjectFacilityHelper, createProjectResourceHelper +}; diff --git a/health-services/project-factory/src/server/config/constants.ts b/health-services/project-factory/src/server/config/constants.ts index fffa89a7c87..5023c9de00b 100644 --- a/health-services/project-factory/src/server/config/constants.ts +++ b/health-services/project-factory/src/server/config/constants.ts @@ -10,7 +10,8 @@ export const CONSTANTS: any = { INVALID_PAGINATION: "Invalid pagination", KAFKA_ERROR: "Some error occured in kafka", SCHEMA_ERROR: " Schema related error", - RESPONSE_NOT_FOUND_ERROR: "Response not found" + RESPONSE_NOT_FOUND_ERROR: "Response not found", + GENERATE_ERROR: "Error while generating user/facility/boundary" }, FILE: { INVALID_FILE: "No download URL returned for the given fileStoreId", @@ -32,7 +33,8 @@ export const CONSTANTS: any = { CAMPAIGN_NOT_FOUND: "Campaign not found", GENERATION_REQUIRE: "First generate then download", RESOURCE_CREATION_ERROR: "Some error occured during resource creation", - CAMPAIGN_NAME_ERROR: "Campaign name already exists" + CAMPAIGN_NAME_ERROR: "Campaign name already exists", + CAMPAIGN_ALREADY_MAPPED: "Campaign is already mapped", }, BOUNDARY: { BOUNDARY_DATA_NOT_FOUND: "No boundary data found in the system.", @@ -108,6 +110,41 @@ export const generatedResourceStatuses: any = { expired: "expired" } +export const processTrackTypes = { + validation: "validation", + triggerResourceCreation: "trigger-resource-creation", + facilityCreation: "facility-creation", + staffCreation: "staff-creation", + targetAndDeliveryRulesCreation: "target-and-delivery-rules-creation", + confirmingResourceCreation: "confirming-resource-creation", + prepareResourceForMapping: "prepare-resource-for-mapping", + validateMappingResource: "validate-mapping-resource", + staffMapping: "staff-mapping", + resourceMapping: "resource-mapping", + facilityMapping: "facility-mapping", + campaignCreation: "campaign-creation", + error: "error" +} + +export const processTrackForUi = [ + processTrackTypes.facilityCreation, + processTrackTypes.staffCreation, + processTrackTypes.targetAndDeliveryRulesCreation, + processTrackTypes.staffMapping, + processTrackTypes.resourceMapping, + processTrackTypes.facilityMapping, + processTrackTypes.campaignCreation, + processTrackTypes.error +]; + + +export const processTrackStatuses = { + inprogress: "inprogress", + completed: "completed", + toBeCompleted: "toBeCompleted", + failed: "failed", +} + // Retrieves the error object containing the error code, message, and notFound flag. export const getErrorCodes = (module: string, key: string): Error => { diff --git a/health-services/project-factory/src/server/config/createAndSearch.ts b/health-services/project-factory/src/server/config/createAndSearch.ts index d89c45b7606..8fb63b1be9f 100644 --- a/health-services/project-factory/src/server/config/createAndSearch.ts +++ b/health-services/project-factory/src/server/config/createAndSearch.ts @@ -132,6 +132,138 @@ const createAndSearch: any = { searchPath: "Facilities" } }, + "facilityMicroplan": { + requiresToSearchFromSheet: [ + { + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + searchPath: "Facility.id" + } + ], + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + }, + sheetSchema: { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "FacilityTemplateSchema", + "type": "object", + "properties": { + "Facility Name": { + "type": "string", + "maxLength": 2000, + "minLength": 1 + }, + "Facility Type": { + // "type": "string", + "enum": ["Warehouse", "Health Facility", "Storing Resource"] + }, + "Facility Status": { + // "type": "string", + "enum": ["Temporary", "Permanent"] + }, + "Capacity": { + "type": "number", + "minimum": 1, + "maximum": 100000000 + } + }, + "required": [ + "Facility Name", + "Facility Type", + "Facility Status", + "Capacity" + ], + "unique": [ + "Facility Name" + ] + }, + uniqueIdentifier: "id", + uniqueIdentifierColumn: "A", + activeColumn: "F", + activeColumnName: "HCM_ADMIN_CONSOLE_FACILITY_USAGE_MICROPLAN", + uniqueIdentifierColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + matchEachKey: true, + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_FACILITIES", + parseLogic: [ + { + sheetColumn: "A", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + resultantPath: "id", + type: "string" + }, + { + sheetColumn: "B", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_NAME_MICROPLAN", + resultantPath: "name", + type: "string" + }, + { + sheetColumn: "C", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_TYPE_MICROPLAN", + resultantPath: "usage", + type: "string" + }, + { + sheetColumn: "D", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_STATUS_MICROPLAN", + resultantPath: "isPermanent", + type: "boolean", + conversionCondition: { + "Permanent": "true", + "Temporary": "" + } + }, + { + sheetColumn: "E", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN", + resultantPath: "storageCapacity", + type: "number" + }, + { + sheetColumn: "J", + sheetColumnName: "HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN" + } + ], + tenantId: { + getValueViaPath: "ResourceDetails.tenantId", + resultantPath: "tenantId" + } + }, + createBulkDetails: { + limit: 50, + createPath: "Facilities", + url: config.host.facilityHost + "facility/v1/bulk/_create" + }, + searchDetails: { + searchElements: [ + { + keyPath: "tenantId", + getValueViaPath: "ResourceDetails.tenantId", + isInParams: true, + isInBody: false, + }, + { + keyPath: "Facility", + isInParams: false, + isInBody: true, + } + ], + searchLimit: { + keyPath: "limit", + value: "200", + isInParams: true, + isInBody: false, + }, + searchOffset: { + keyPath: "offset", + value: "0", + isInParams: true, + isInBody: false, + }, + url: config.host.facilityHost + "facility/v1/_search", + searchPath: "Facilities" + } + }, "boundary": { parseArrayConfig: { sheetName: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", diff --git a/health-services/project-factory/src/server/config/index.ts b/health-services/project-factory/src/server/config/index.ts index 07286afac9e..7260b93c59d 100644 --- a/health-services/project-factory/src/server/config/index.ts +++ b/health-services/project-factory/src/server/config/index.ts @@ -16,7 +16,14 @@ const getDBSchemaName = (dbSchema = "") => { } // Configuration object containing various environment variables const config = { + cacheTime : 300, + enableDynamicTemplateFor: process.env.ENABLE_DYNAMIC_TEMPLATE_FOR || "", + isCallGenerateWhenDeliveryConditionsDiffer: (process.env.IS_CALL_GENERATE_WHEN_DELIVERY_CONDITIONS_DIFFER === "true") || false, + prefixForMicroplanCampaigns: "MP", + excludeHierarchyTypeFromBoundaryCodes: (process.env.EXCLUDE_HIERARCHY_TYPE_FROM_BOUNDARY_CODES === "true") || false, + excludeBoundaryNameAtLastFromBoundaryCodes: (process.env.EXCLUDE_BOUNDARY_NAME_AT_LAST_FROM_BOUNDARY_CODES === "true") || false, masterNameForSchemaOfColumnHeaders: "adminSchema", + masterNameForSplitBoundariesOn: "hierarchyConfig", boundary: { boundaryCode: process.env.BOUNDARY_CODE_HEADER_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", boundaryTab: process.env.BOUNDARY_TAB_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", @@ -35,6 +42,7 @@ const config = { userSchemaMasterName: process.env.USER_SCHEMA_MASTER || "userSchema", userDefaultPassword: process.env.USER_DEFAULT_PASSWORD || "eGov@123", userPasswordAutoGenerate: process.env.USER_PASSWORD_AUTO_GENERATE || "true", + mapUserViaCommonParent: process.env.MAP_USER_VIA_COMMON_PARENT || false, }, cacheValues: { cacheEnabled: process.env.CACHE_ENABLED, @@ -44,7 +52,7 @@ const config = { kafka: { // Kafka topics KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "save-project-campaign-details", - KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "update-project-campaign-details", + KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "update-project-campaign-details", KAFKA_START_CAMPAIGN_MAPPING_TOPIC: process.env.KAFKA_START_CAMPAIGN_MAPPING_TOPIC || "start-campaign-mapping", KAFKA_UPDATE_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_UPDATE_CAMPAIGN_DETAILS_TOPIC || "update-campaign-details", KAFKA_CREATE_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC || "create-resource-details", @@ -54,6 +62,7 @@ const config = { KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC || "create-generated-resource-details", KAFKA_SAVE_PROCESS_TRACK_TOPIC: process.env.KAFKA_SAVE_PROCESS_TRACK_TOPIC || "save-process-track", KAFKA_UPDATE_PROCESS_TRACK_TOPIC: process.env.KAFKA_UPDATE_PROCESS_TRACK_TOPIC || "update-process-track", + KAFKA_TEST_TOPIC: "test-topic-project-factory", }, // Database configuration diff --git a/health-services/project-factory/src/server/config/models/createRequestSchema.ts b/health-services/project-factory/src/server/config/models/createRequestSchema.ts index ed56e706d16..18a96101fbd 100644 --- a/health-services/project-factory/src/server/config/models/createRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/createRequestSchema.ts @@ -4,7 +4,7 @@ export const createRequestSchema = { "properties": { "type": { "type": "string", - "enum": ["boundary", "facility", "user", "boundaryWithTarget"] + "enum": ["boundary", "facility", "user", "boundaryWithTarget","facilityMicroplan"] }, "tenantId": { "type": "string", diff --git a/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts index b47e714dac5..d23b7df2f4f 100644 --- a/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts @@ -5,7 +5,7 @@ export const downloadRequestSchema = { "tenantId": { "type": "string", "maxLength": 128, - "minLength": 1, + "minLength": 1 }, "type": { "type": "string", @@ -22,14 +22,24 @@ export const downloadRequestSchema = { "hierarchyType": { "type": "string", "maxLength": 128, - "minLength": 1, + "minLength": 1 }, "id": { "type": "string", - "maxlength": 128, - "minLength": 1, + "maxLength": 128, + "minLength": 1 + }, + "status": { + "type": "string", + "maxLength": 500, + "minLength": 1 + }, + "campaignId": { + "type": "string", + "maxLength": 128, + "minLength": 1 } }, "required": ["tenantId", "type", "hierarchyType"], "additionalProperties": false -} \ No newline at end of file +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts index cc1df4b70e6..4ca530f9393 100644 --- a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts @@ -12,8 +12,6 @@ export const generateRequestSchema = { "maxLength": 128, "minLength": 1, "enum": [ - "facility", - "user", "boundary", "facilityWithBoundary", "userWithBoundary" diff --git a/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts index 384735fb683..dc3232294e2 100644 --- a/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts +++ b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts @@ -1,5 +1,5 @@ import * as express from "express"; -import { createCampaignService, createProjectTypeCampaignService, searchProjectTypeCampaignService, updateProjectTypeCampaignService } from "../../service/campaignManageService"; +import { createCampaignService, createProjectTypeCampaignService, searchProcessTracksService, searchProjectTypeCampaignService, updateProjectTypeCampaignService } from "../../service/campaignManageService"; import { logger } from "../../utils/logger"; import { errorResponder, sendResponse } from "../../utils/genericUtils"; @@ -23,6 +23,7 @@ class campaignManageController { this.router.post(`${this.path}/update`, this.updateProjectTypeCampaign); this.router.post(`${this.path}/search`, this.searchProjectTypeCampaign); this.router.post(`${this.path}/createCampaign`, this.createCampaign); + this.router.post(`${this.path}/getProcessTrack`, this.searchProcessTracks); } /** * Handles the creation of a project type campaign. @@ -111,6 +112,24 @@ class campaignManageController { } }; + searchProcessTracks = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROCESS SEARCH REQUEST"); + const processTrack = await searchProcessTracksService(request); + // Send response with campaign details + return sendResponse(response, { processTrack }, request); + } + catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + }; export default campaignManageController; diff --git a/health-services/project-factory/src/server/kafka/Listener.ts b/health-services/project-factory/src/server/kafka/Listener.ts index ac91786b621..128f99c08cb 100644 --- a/health-services/project-factory/src/server/kafka/Listener.ts +++ b/health-services/project-factory/src/server/kafka/Listener.ts @@ -1,105 +1,55 @@ -import { Message ,ConsumerGroup, ConsumerGroupOptions} from 'kafka-node'; +import { ConsumerGroup, ConsumerGroupOptions, Message } from 'kafka-node'; import config from '../config'; -import { getFormattedStringForDebug, logger } from '../utils/logger'; // Importing logger utility for logging -import { producer } from './Producer'; // Importing producer from the Producer module -import { processCampaignMapping } from '../utils/campaignMappingUtils'; -import { enrichAndPersistCampaignWithError } from '../utils/campaignUtils'; -import { throwError } from '../utils/genericUtils'; +import { getFormattedStringForDebug, logger } from '../utils/logger'; +import { shutdownGracefully } from '../utils/genericUtils'; +import { handleCampaignMapping } from '../utils/campaignMappingUtils'; - - -// Replace with the correct Kafka broker(s) and topic name -const kafkaConfig:ConsumerGroupOptions = { - kafkaHost: config?.host?.KAFKA_BROKER_HOST, // Use the correct broker address and port +// Kafka Configuration +const kafkaConfig: ConsumerGroupOptions = { + kafkaHost: config?.host?.KAFKA_BROKER_HOST, groupId: 'project-factory', autoCommit: true, autoCommitIntervalMs: 5000, fromOffset: 'latest', - }; -const topicName = config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC; - -// Create a Kafka client -// const kafkaClient = new KafkaClient(kafkaConfig); - -// Create a Kafka consumer -// const consumer = new Consumer(kafkaClient, [{ topic: topicName, partition: 0 }], { autoCommit: true }); - +// Topic Names +const topicNames = [ + config.kafka.KAFKA_START_CAMPAIGN_MAPPING_TOPIC, + config.kafka.KAFKA_TEST_TOPIC +]; -const consumerGroup=new ConsumerGroup(kafkaConfig, topicName) +// Consumer Group Initialization +const consumerGroup = new ConsumerGroup(kafkaConfig, topicNames); -// Exported listener function +// Kafka Listener export function listener() { - // Set up a message event handler consumerGroup.on('message', async (message: Message) => { try { - // Parse the message value as an array of objects - const messageObject: any = JSON.parse(message.value?.toString() || '{}'); - try { - // await processCampaignMapping(messageObject); - logger.info("Received a messageObject for campaign mapping : "); - logger.debug("Message Object of campaign mapping :: " + getFormattedStringForDebug(messageObject)); - await processCampaignMapping(messageObject); - } catch (error: any) { - console.log(error) - logger.error(error) - enrichAndPersistCampaignWithError(messageObject, error) + const messageObject = JSON.parse(message.value?.toString() || '{}'); + + switch (message.topic) { + case config.kafka.KAFKA_START_CAMPAIGN_MAPPING_TOPIC: + await handleCampaignMapping(messageObject); + break; + default: + logger.warn(`Unhandled topic: ${message.topic}`); } - logger.info(`KAFKA :: LISTENER :: Received a message`); - logger.debug(`KAFKA :: LISTENER :: message ${getFormattedStringForDebug(messageObject)}`); + + logger.info(`KAFKA :: LISTENER :: Received a message from topic ${message.topic}`); + logger.debug(`KAFKA :: LISTENER :: Message: ${getFormattedStringForDebug(messageObject)}`); } catch (error) { - logger.info('KAFKA :: LISTENER :: Some Error Occurred '); // Log successful message production - logger.error(`KAFKA :: LISTENER :: Error : ${JSON.stringify(error)}`); // Log producer error - console.log(error) + logger.error(`KAFKA :: LISTENER :: Error processing message: ${error}`); + console.error(error); } }); - // Set up error event handlers consumerGroup.on('error', (err) => { - console.error(`Consumer Error: ${err}`); + logger.error(`Consumer Error: ${err}`); + shutdownGracefully(); }); consumerGroup.on('offsetOutOfRange', (err) => { - console.error(`Offset out of range error: ${err}`); + logger.error(`Offset out of range error: ${err}`); }); } - - -/** - * Produces modified messages to a specified Kafka topic. - * @param modifiedMessages An array of modified messages to be produced. - * @param topic The Kafka topic to which the messages will be produced. - * @returns A promise that resolves when the messages are successfully produced. - */ -async function produceModifiedMessages(modifiedMessages: any[], topic: any) { - try { - logger.info(`KAFKA :: PRODUCER :: a message sent to topic ${topic}`); - logger.debug(`KAFKA :: PRODUCER :: message ${getFormattedStringForDebug(modifiedMessages)}`); - return new Promise((resolve, reject) => { - const payloads = [ - { - topic: topic, - messages: JSON.stringify(modifiedMessages), // Convert modified messages to JSON string - }, - ]; - - // Send payloads to the Kafka producer - producer.send(payloads, (err) => { - if (err) { - logger.info('KAFKA :: PRODUCER :: Some Error Occurred '); - logger.error(`KAFKA :: PRODUCER :: Error : ${JSON.stringify(err)}`); - // reject(err); // Reject promise if there's an error - } else { - logger.info('KAFKA :: PRODUCER :: message sent successfully '); - // resolve(); // Resolve promise if messages are successfully produced - } - }); - }); - } catch (error) { - logger.error(`KAFKA :: PRODUCER :: Exception caught: ${JSON.stringify(error)}`); - throwError("COMMON", 400, "KAKFA_ERROR", "Some error occured in kafka"); // Re-throw the error after logging it - } -} - -export { produceModifiedMessages } // Export the produceModifiedMessages function for external use diff --git a/health-services/project-factory/src/server/kafka/Producer.ts b/health-services/project-factory/src/server/kafka/Producer.ts index b728b48a2ca..dc19acc2fa1 100644 --- a/health-services/project-factory/src/server/kafka/Producer.ts +++ b/health-services/project-factory/src/server/kafka/Producer.ts @@ -1,25 +1,111 @@ -import config from '../config'; // Importing configuration settings -import { Producer, KafkaClient } from 'kafka-node'; // Importing Producer and KafkaClient from 'kafka-node' library +import { Producer, KafkaClient } from 'kafka-node'; import { logger } from "../utils/logger"; +import { shutdownGracefully, throwError } from '../utils/genericUtils'; +import config from '../config'; -// Creating a new Kafka client instance using the configured Kafka broker host -const kafkaClient = new KafkaClient({ - kafkaHost: config?.host?.KAFKA_BROKER_HOST, // Configuring Kafka broker host - connectRetryOptions: { retries: 1 }, // Configuring connection retry options -}); +let kafkaClient: KafkaClient; +let producer: Producer; -// Creating a new Kafka producer instance using the Kafka client -const producer = new Producer(kafkaClient, { partitionerType: 2 }); // Using partitioner type 2 +const createKafkaClientAndProducer = () => { + kafkaClient = new KafkaClient({ + kafkaHost: config?.host?.KAFKA_BROKER_HOST, + connectRetryOptions: { retries: 1 }, + }); -// Event listener for 'ready' event, indicating that the producer is ready to send messages -producer.on('ready', () => { - logger.info('Producer is ready'); // Log message indicating producer is ready -}); + // Event listener for 'error' event, indicating that the client encountered an error + kafkaClient.on('error', (err: any) => { + logger.error('Kafka client is in error state'); // Log message indicating client is in error state + console.error(err.stack || err); // Log the error stack or message + shutdownGracefully(); + }); -// Event listener for 'error' event, indicating that the producer encountered an error -producer.on('error', (err) => { - logger.error('Producer is in error state'); // Log message indicating producer is in error state - console.error(err.stack || err); // Log the error stack or message -}); + producer = new Producer(kafkaClient, { partitionerType: 2 }); -export { producer }; // Exporting the producer instance for external use + producer.on('ready', () => { + logger.info('Producer is ready'); + checkBrokerAvailability(); + }); + + producer.on('error', (err: any) => { + logger.error('Producer is in error state'); + console.error(err); + shutdownGracefully(); + }); +}; + +// Function to check broker availability by listing all brokers +const checkBrokerAvailability = () => { + kafkaClient.loadMetadataForTopics([], (err: any, data: any) => { + if (err) { + logger.error('Error checking broker availability:', err); + shutdownGracefully(); + } else { + const brokers = data[1]?.metadata || {}; + const brokerCount = Object.keys(brokers).length; + logger.info('Broker count:' + String(brokerCount)); + + if (brokerCount <= 0) { + logger.error('No brokers found. Shutting down the service.'); + shutdownGracefully(); + } else { + logger.info('Brokers are available:', brokers); + } + } + }); +}; + + +createKafkaClientAndProducer(); + +const sendWithRetries = (payloads: any[], retries = 3, shutdown: boolean = false): Promise => { + return new Promise((resolve, reject) => { + producer.send(payloads, async (err: any) => { + if (err) { + logger.error('Error sending message:', err); + logger.debug(`Was trying to send: ${JSON.stringify(payloads)}`); + if (retries > 0) { + logger.info(`Retrying to send message. Retries left: ${retries}`); + await new Promise(resolve => setTimeout(resolve, 2000)); // wait before retrying + resolve(sendWithRetries(payloads, retries - 1, shutdown)); + } else { + // Attempt to reconnect and retry + logger.error('Failed to send message after retries. Reconnecting producer...'); + if (shutdown) { + shutdownGracefully(); + } + else { + producer.close(() => { + createKafkaClientAndProducer(); + setTimeout(() => { + sendWithRetries(payloads, 1, true).catch(reject); + }, 2000); // wait before retrying after reconnect + }); + } + } + } else { + logger.info('Message sent successfully'); + resolve(); + } + }); + }); +}; + +async function produceModifiedMessages(modifiedMessages: any[], topic: any) { + try { + logger.info(`KAFKA :: PRODUCER :: A message sent to topic ${topic}`); + logger.debug(`KAFKA :: PRODUCER :: Message ${JSON.stringify(modifiedMessages)}`); + const payloads = [ + { + topic: topic, + messages: JSON.stringify(modifiedMessages), + }, + ]; + + await sendWithRetries(payloads, 3); + } catch (error) { + logger.error(`KAFKA :: PRODUCER :: Exception caught: ${JSON.stringify(error)}`); + throwError("COMMON", 400, "KAFKA_ERROR", "Some error occurred in Kafka"); // Re-throw the error after logging it + } +} + +export { produceModifiedMessages }; diff --git a/health-services/project-factory/src/server/service/campaignManageService.ts b/health-services/project-factory/src/server/service/campaignManageService.ts index 3d3652bb441..4b397e8b28f 100644 --- a/health-services/project-factory/src/server/service/campaignManageService.ts +++ b/health-services/project-factory/src/server/service/campaignManageService.ts @@ -1,10 +1,11 @@ import express from "express"; import { processBasedOnAction, searchProjectCampaignResourcData } from "../utils/campaignUtils"; import { logger } from "../utils/logger"; -import { validateProjectCampaignRequest, validateSearchProjectCampaignRequest } from "../validators/campaignValidators"; +import { validateProjectCampaignRequest, validateSearchProcessTracksRequest, validateSearchProjectCampaignRequest } from "../validators/campaignValidators"; import { validateCampaignRequest } from "../validators/genericValidator"; import { createRelatedResouce } from "../api/genericApis"; import { enrichCampaign } from "../api/campaignApis"; +import { getProcessDetails, modifyProcessDetails } from "../utils/processTrackUtils"; async function createProjectTypeCampaignService(request: express.Request) { // Validate the request for creating a project type campaign @@ -53,10 +54,26 @@ async function createCampaignService( return requestBody?.Campaign }; +async function searchProcessTracksService( + request: express.Request +) { + await validateSearchProcessTracksRequest(request) + logger.info("VALIDATED THE PROCESS SEARCH REQUEST"); + + // Search and return related process tracks + const processDetailsArray = await getProcessDetails(request?.query?.campaignId as string) + + // sort and modify process details so that details with status as toBeCompleted comes in last + const resultArray = modifyProcessDetails(processDetailsArray) + + return resultArray +}; + export { createProjectTypeCampaignService, updateProjectTypeCampaignService, searchProjectTypeCampaignService, - createCampaignService -} \ No newline at end of file + createCampaignService, + searchProcessTracksService +} diff --git a/health-services/project-factory/src/server/service/dataManageService.ts b/health-services/project-factory/src/server/service/dataManageService.ts index ed224dc824f..f6ad7105f65 100644 --- a/health-services/project-factory/src/server/service/dataManageService.ts +++ b/health-services/project-factory/src/server/service/dataManageService.ts @@ -3,12 +3,15 @@ import { processGenericRequest } from "../api/campaignApis"; import { createAndUploadFile, getBoundarySheetData } from "../api/genericApis"; import { getLocalizedName, processDataSearchRequest } from "../utils/campaignUtils"; import { addDataToSheet, enrichResourceDetails, getLocalizedMessagesHandler, searchGeneratedResources, processGenerate, throwError } from "../utils/genericUtils"; -import { logger } from "../utils/logger"; +import { getFormattedStringForDebug, logger } from "../utils/logger"; import { validateCreateRequest, validateDownloadRequest, validateSearchRequest } from "../validators/campaignValidators"; import { validateGenerateRequest } from "../validators/genericValidator"; import { getLocalisationModuleName } from "../utils/localisationUtils"; import { getBoundaryTabName } from "../utils/boundaryUtils"; import { getNewExcelWorkbook } from "../utils/excelUtils"; +import { redis, checkRedisConnection } from "../utils/redisUtils"; // Importing checkRedisConnection function +import config from '../config/index' + const generateDataService = async (request: express.Request) => { @@ -38,24 +41,48 @@ const downloadDataService = async (request: express.Request) => { } const getBoundaryDataService = async ( - request: express.Request) => { + request: express.Request, enableCaching = false) => { try { + const { hierarchyType, campaignId } = request?.query; + const cacheTTL = config?.cacheTime; // TTL in seconds (5 minutes) + const cacheKey = `${campaignId}-${hierarchyType}`; + let isRedisConnected = false; + let cachedData: any = null; + if (cacheKey && enableCaching) { + isRedisConnected = await checkRedisConnection(); + cachedData = await redis.get(cacheKey); // Get cached data + } + if (cachedData) { + logger.info("CACHE HIT :: " + cacheKey); + logger.debug(`CACHED DATA :: ${getFormattedStringForDebug(cachedData)}`); + + // Reset the TTL for the cache key + if (config.cacheValues.resetCache) { + await redis.expire(cacheKey, cacheTTL); + } + + return JSON.parse(cachedData); // Return parsed cached data if available + } else { + logger.info("NO CACHE FOUND :: REQUEST :: " + cacheKey); + } const workbook = getNewExcelWorkbook(); - const { hierarchyType } = request?.query; const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; // Retrieve boundary sheet data const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); - const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); addDataToSheet(boundarySheet, boundarySheetData); - const BoundaryFileDetails: any = await createAndUploadFile(workbook, request); + const boundaryFileDetails: any = await createAndUploadFile(workbook, request); // Return boundary file details logger.info("RETURNS THE BOUNDARY RESPONSE"); - return BoundaryFileDetails; + if (cacheKey && isRedisConnected) { + await redis.set(cacheKey, JSON.stringify(boundaryFileDetails), "EX", cacheTTL); // Cache the response data with TTL + } + return boundaryFileDetails; } catch (e: any) { + console.log(e) logger.error(String(e)) // Handle errors and send error response throw (e); diff --git a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts index ac34761d2f8..f4698f4b77d 100644 --- a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts @@ -1,12 +1,15 @@ import createAndSearch from "../config/createAndSearch"; import config from "../config"; -import { getDataFromSheet, throwError } from "./genericUtils"; +import { getDataFromSheet, getLocalizedMessagesHandlerViaRequestInfo, throwError } from "./genericUtils"; import { getFormattedStringForDebug, logger } from "./logger"; -import { httpRequest } from "./request"; -import { produceModifiedMessages } from "../kafka/Listener"; -import { getLocalizedName } from "./campaignUtils"; +import { defaultheader, httpRequest } from "./request"; +import { produceModifiedMessages } from "../kafka/Producer"; +import { enrichAndPersistCampaignWithError, getLocalizedName } from "./campaignUtils"; import { campaignStatuses, resourceDataStatuses } from "../config/constants"; import { createCampaignService } from "../service/campaignManageService"; +import { persistTrack } from "./processTrackUtils"; +import { processTrackTypes, processTrackStatuses } from "../config/constants"; +import { createProjectFacilityHelper, createProjectResourceHelper, createStaffHelper } from "../api/genericApis"; async function createBoundaryWithProjectMapping(projects: any, boundaryWithProject: any) { @@ -36,8 +39,107 @@ function getPvarIds(messageObject: any) { return Array.from(uniquePvarIds); // Convert Set to array before returning } +function trimBoundaryCodes(root: any) { + if (root) { + root.code = root.code.trim(); // Trim the code + + // Recursively trim the codes in the children + for (const child of root.children) { + trimBoundaryCodes(child); + } + } +} + +async function getAllBoundaries(messageObject: any, tenantId: any, rootBoundary: any, hierarchyType: any) { + const BoundarySearchBody = { + RequestInfo: messageObject?.RequestInfo, + } + const params = { + tenantId, + codes: rootBoundary, + hierarchyType, + includeChildren: true + } + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + } + const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, BoundarySearchBody, params, undefined, undefined, header); + trimBoundaryCodes(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]); + return boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0] +} + +// Function to find the path to a given boundary code +function findPath(root: any, code: string, path: any[] = []) { + if (root.code === code) { + return [...path, root]; + } + for (const child of root.children) { + const result: any = findPath(child, code, [...path, root]); + if (result) return result; + } + return null; +} + +// Function to find the common parent for multiple codes +function findCommonParent(codes: string[], root: any) { + if (codes.length === 0) return null; + + // Find paths for all codes + const paths = codes.map(code => findPath(root, code)).filter(path => path !== null); + + if (paths.length === 0) return null; + + // Compare paths to find the common ancestor + let commonParent: any = null; + + for (let i = 0; i < Math.min(...paths.map(path => path.length)); i++) { + const currentParent = paths[0][i]; + if (paths.every(path => path[i] && path[i].code === currentParent.code)) { + commonParent = currentParent; + } else { + break; + } + } + + return commonParent?.code; +} + +function mapBoundaryCodes(resource: any, code: string, boundaryCode: string, boundaryCodes: any, allBoundaries: any) { + // Split boundary codes if they have comma separated values + const boundaryCodesArray = boundaryCode.split(',').map((bc: string) => bc.trim()); + if (resource?.type == "user" && boundaryCodesArray?.length > 1 && config.user.mapUserViaCommonParent) { + const commonParent = findCommonParent(boundaryCodesArray, allBoundaries); + if (commonParent) { + logger.info(`Boundary Codes Array ${boundaryCodesArray.join(",")} for resource ${resource?.type} has common parent ${commonParent}`) + if (!boundaryCodes[resource?.type]) { + boundaryCodes[resource?.type] = {}; + } + if (!boundaryCodes[resource?.type][commonParent]) { + boundaryCodes[resource?.type][commonParent] = []; + } + boundaryCodes[resource?.type][commonParent].push(code); + logger.info(`Common Parent Boundary code ${commonParent} mapped to resource ${resource?.type} with code ${code}`) + } + } + else { + boundaryCodesArray.forEach((trimmedBC: string) => { + // Trim any leading or trailing spaces + if (!boundaryCodes[resource?.type]) { + boundaryCodes[resource?.type] = {}; + } + if (!boundaryCodes[resource?.type][trimmedBC]) { + boundaryCodes[resource?.type][trimmedBC] = []; + } + boundaryCodes[resource?.type][trimmedBC].push(code); + logger.info(`Boundary code ${trimmedBC} mapped to resource ${resource?.type} with code ${code}`) + }); + } +} + async function enrichBoundaryCodes(resources: any[], messageObject: any, boundaryCodes: any, sheetName: any) { const localizationMap: any = messageObject?.localizationMap + const allBoundaries = await getAllBoundaries(messageObject, messageObject?.Campaign?.tenantId, messageObject?.Campaign?.boundaryCode, messageObject?.Campaign?.hierarchyType); for (const resource of resources) { const processedFilestoreId = resource?.processedFilestoreId; if (processedFilestoreId) { @@ -54,20 +156,7 @@ async function enrichBoundaryCodes(resources: any[], messageObject: any, boundar active = data[activeColumn]; } if (boundaryCode && active == "Active") { - // Split boundary codes if they have comma separated values - const boundaryCodesArray = boundaryCode.split(','); - boundaryCodesArray.forEach((bc: string) => { - // Trim any leading or trailing spaces - const trimmedBC = bc.trim(); - if (!boundaryCodes[resource?.type]) { - boundaryCodes[resource?.type] = {}; - } - if (!boundaryCodes[resource?.type][trimmedBC]) { - boundaryCodes[resource?.type][trimmedBC] = []; - } - boundaryCodes[resource?.type][trimmedBC].push(code); - logger.info(`Boundary code ${trimmedBC} mapped to resource ${resource?.type} with code ${code}`) - }); + mapBoundaryCodes(resource, code, boundaryCode, boundaryCodes, allBoundaries); } } else { @@ -134,34 +223,39 @@ async function getProjectMappingBody(messageObject: any, boundaryWithProject: an } return { RequestInfo: messageObject?.RequestInfo, - Campaign: Campaign + Campaign: Campaign, + CampaignDetails: messageObject?.CampaignDetails } } async function fetchAndMap(resources: any[], messageObject: any) { - const localizationMap = messageObject?.localizationMap; - const sheetName: any = { - "user": getLocalizedName(createAndSearch?.user?.parseArrayConfig?.sheetName, localizationMap), - "facility": getLocalizedName(createAndSearch?.facility?.parseArrayConfig?.sheetName, localizationMap) - } - // Object to store boundary codes - const boundaryCodes: any = {}; + await persistTrack(messageObject?.Campaign?.id, processTrackTypes.prepareResourceForMapping, processTrackStatuses.inprogress) + const localizationMap = await getLocalizedMessagesHandlerViaRequestInfo(messageObject?.RequestInfo, messageObject?.Campaign?.tenantId); + messageObject.localizationMap = localizationMap + try { + const localizationMap = messageObject?.localizationMap; + const sheetName: any = { + "user": getLocalizedName(createAndSearch?.user?.parseArrayConfig?.sheetName, localizationMap), + "facility": getLocalizedName(createAndSearch?.facility?.parseArrayConfig?.sheetName, localizationMap) + } + // Object to store boundary codes + const boundaryCodes: any = {}; - await enrichBoundaryCodes(resources, messageObject, boundaryCodes, sheetName); - logger.info("boundaryCodes : " + JSON.stringify(boundaryCodes)); - var boundaryWithProject: any = {}; - await enrichBoundaryWithProject(messageObject, boundaryWithProject, boundaryCodes); - logger.info("boundaryWithProject : " + JSON.stringify(boundaryWithProject)); - const projectMappingBody = await getProjectMappingBody(messageObject, boundaryWithProject, boundaryCodes); - logger.info("projectMappingBody : " + JSON.stringify(projectMappingBody)); - logger.info("projectMapping started "); - const projectMappingResponse: any = await createCampaignService(projectMappingBody); - logger.info("Project Mapping Response received"); - if (projectMappingResponse) { - logger.info("Campaign Mapping done") - messageObject.CampaignDetails.status = campaignStatuses.inprogress - produceModifiedMessages(messageObject, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC) + await enrichBoundaryCodes(resources, messageObject, boundaryCodes, sheetName); + logger.info("boundaryCodes : " + JSON.stringify(boundaryCodes)); + var boundaryWithProject: any = {}; + await enrichBoundaryWithProject(messageObject, boundaryWithProject, boundaryCodes); + logger.info("boundaryWithProject : " + JSON.stringify(boundaryWithProject)); + var projectMappingBody = await getProjectMappingBody(messageObject, boundaryWithProject, boundaryCodes); + logger.info("projectMappingBody : " + JSON.stringify(projectMappingBody)); + logger.info("projectMapping started "); + } catch (error: any) { + console.log(error) + await persistTrack(messageObject?.Campaign?.id, processTrackTypes.prepareResourceForMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) } + await persistTrack(messageObject?.Campaign?.id, processTrackTypes.prepareResourceForMapping, processTrackStatuses.completed) + await createCampaignService(projectMappingBody); } async function searchResourceDetailsById(resourceDetailId: string, messageObject: any) { @@ -202,45 +296,150 @@ async function processCampaignMapping(messageObject: any) { logger.info("Campaign Already In Progress and Mapped"); } else { - var completedResources: any = [] - var resources = []; - for (const resourceDetailId of resourceDetailsIds) { - var retry = 75; - while (retry--) { - const response = await searchResourceDetailsById(resourceDetailId, messageObject); - logger.info(`response for resourceDetailId: ${resourceDetailId}`); - logger.debug(` response : ${getFormattedStringForDebug(response)}`) - if (response?.status == "invalid") { - logger.error(`resource with id ${resourceDetailId} is invalid`); - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + resourceDetailId + " is invalid"); - break; - } - else if (response?.status == resourceDataStatuses.failed) { - logger.error(`resource with id ${resourceDetailId} is ${resourceDataStatuses.failed}`); - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", `resource with id ${resourceDetailId} is ${resourceDataStatuses.failed} : with errorlog ${response?.additionalDetails?.error}`); - break; - } - else if (response?.status == resourceDataStatuses.completed) { - completedResources.push(resourceDetailId); - resources.push(response); - break; - } - else { - logger.info(`Waiting for 20 seconds for resource with id ${resourceDetailId} on retry ${retry}`); - await new Promise(resolve => setTimeout(resolve, 20000)); + await persistTrack(id, processTrackTypes.confirmingResourceCreation, processTrackStatuses.inprogress); + try { + var completedResources: any = [] + var resources = []; + for (const resourceDetailId of resourceDetailsIds) { + var retry = 75; + while (retry--) { + const response = await searchResourceDetailsById(resourceDetailId, messageObject); + logger.info(`response for resourceDetailId: ${resourceDetailId}`); + logger.debug(` response : ${getFormattedStringForDebug(response)}`) + if (response?.status == "invalid") { + logger.error(`resource type ${response?.type} is invalid`); + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Data File for resource type " + response?.type + " is invalid"); + break; + } + else if (response?.status == resourceDataStatuses.failed) { + logger.error(`resource type ${response?.type} is ${resourceDataStatuses.failed}`); + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", `Resource creation of type ${response?.type} failed : with errorlog ${response?.additionalDetails?.error}`); + break; + } + else if (response?.status == resourceDataStatuses.completed) { + completedResources.push(resourceDetailId); + resources.push(response); + break; + } + else { + logger.info(`Waiting for 20 seconds for resource with id ${resourceDetailId} on retry ${retry}`); + await new Promise(resolve => setTimeout(resolve, 20000)); + } } } + var uncompletedResourceIds = resourceDetailsIds?.filter((x: any) => !completedResources.includes(x)); + logger.info("uncompletedResourceIds " + JSON.stringify(uncompletedResourceIds)); + logger.info("completedResources " + JSON.stringify(completedResources)); + if (uncompletedResourceIds?.length > 0) { + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + JSON.stringify(uncompletedResourceIds) + " is not completed after long wait. Check file"); + } + } catch (error: any) { + console.log(error) + await persistTrack(id, processTrackTypes.confirmingResourceCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) } - var uncompletedResourceIds = resourceDetailsIds?.filter((x: any) => !completedResources.includes(x)); - logger.info("uncompletedResourceIds " + JSON.stringify(uncompletedResourceIds)); - logger.info("completedResources " + JSON.stringify(completedResources)); - if (uncompletedResourceIds?.length > 0) { - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + JSON.stringify(uncompletedResourceIds) + " is not validated after long wait. Check file"); - } + await persistTrack(id, processTrackTypes.confirmingResourceCreation, processTrackStatuses.completed); await fetchAndMap(resources, messageObject); } } +export async function handleCampaignMapping(messageObject: any) { + try { + logger.info("Received a message for campaign mapping"); + logger.debug("Message Object of campaign mapping: " + getFormattedStringForDebug(messageObject)); + await processCampaignMapping(messageObject); + } catch (error) { + logger.error("Error in campaign mapping: " + error); + await enrichAndPersistCampaignWithError(messageObject, error); + } +} + +export async function handleStaffMapping(mappingArray: any[], campaignId: string, messageObject: any) { + await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.inprogress); + try { + const promises = [] + logger.debug("Array of staff mapping: " + getFormattedStringForDebug(mappingArray)); + for (const staffMapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId, startDate, endDate } = staffMapping; + for (const resourceId of resource?.resourceIds) { + promises.push(createStaffHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)) + } + } + await Promise.all(promises); + } catch (error: any) { + logger.error("Error in staff mapping: " + error); + await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + await enrichAndPersistCampaignWithError(messageObject, error); + throw new Error(error) + } + await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.completed); +} + +export async function handleResourceMapping(mappingArray: any, campaignId: any, messageObject: any) { + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.inprogress); + try { + const promises = [] + logger.debug("Arrray of resource mapping: " + getFormattedStringForDebug(mappingArray)); + for (const mapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId, startDate, endDate } = mapping; + for (const resourceId of resource?.resourceIds) { + promises.push(createProjectResourceHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)); + } + } + await Promise.all(promises); + } catch (error: any) { + logger.error("Error in resource mapping: " + error); + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + await enrichAndPersistCampaignWithError(messageObject, error); + throw new Error(error) + } + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.completed); +} + +export async function handleFacilityMapping(mappingArray: any, campaignId: any, messageObject: any) { + await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.inprogress); + try { + const promises = [] + logger.debug("Array of facility mapping: " + getFormattedStringForDebug(mappingArray)); + for (const mapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId } = mapping; + for (const resourceId of resource?.resourceIds) { + promises.push(createProjectFacilityHelper(resourceId, projectId, resouceBody, tenantId)); + } + } + await Promise.all(promises); + } catch (error: any) { + logger.error("Error in facility mapping: " + error); + await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + await enrichAndPersistCampaignWithError(messageObject, error); + throw new Error(error) + } + await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.completed); +} + +export async function processMapping(mappingObject: any) { + try { + if (mappingObject?.mappingArray && Array.isArray(mappingObject?.mappingArray) && mappingObject?.mappingArray?.length > 0) { + const resourceMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "resource"); + const facilityMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "facility"); + const staffMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "staff"); + await handleResourceMapping(resourceMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); + await handleFacilityMapping(facilityMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); + await handleStaffMapping(staffMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); + } + logger.info("Mapping completed successfully for campaign: " + mappingObject?.CampaignDetails?.id); + mappingObject.CampaignDetails.status = campaignStatuses.inprogress + const produceMessage: any = { + CampaignDetails: mappingObject?.CampaignDetails + } + await produceModifiedMessages(produceMessage, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC) + await persistTrack(mappingObject?.CampaignDetails?.id, processTrackTypes.campaignCreation, processTrackStatuses.completed) + } catch (error) { + logger.error("Error in campaign mapping: " + error); + await enrichAndPersistCampaignWithError(mappingObject, error); + } +} + export { processCampaignMapping, diff --git a/health-services/project-factory/src/server/utils/campaignUtils.ts b/health-services/project-factory/src/server/utils/campaignUtils.ts index f2b4e1f37ca..1fbf424ecf9 100644 --- a/health-services/project-factory/src/server/utils/campaignUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignUtils.ts @@ -2,9 +2,9 @@ import { defaultheader, httpRequest } from "./request"; import config from "../config/index"; import { v4 as uuidv4 } from 'uuid'; -import { produceModifiedMessages } from '../kafka/Listener' +import { produceModifiedMessages } from "../kafka/Producer"; import { confirmProjectParentCreation, createProjectCampaignResourcData, getCampaignSearchResponse, getHierarchy, handleResouceDetailsError, projectCreate } from "../api/campaignApis"; -import { getCampaignNumber, createAndUploadFile, getSheetData, createExcelSheet, getAutoGeneratedBoundaryCodesHandler, createBoundaryEntities, createBoundaryRelationship, getMDMSV1Data, getTargetSheetDataAfterCode, callMdmsTypeSchema } from "../api/genericApis"; +import { getCampaignNumber, createAndUploadFile, getSheetData, createExcelSheet, getAutoGeneratedBoundaryCodesHandler, createBoundaryEntities, createBoundaryRelationship, getMDMSV1Data, getTargetSheetDataAfterCode, callMdmsTypeSchema, getSheetDataFromWorksheet } from "../api/genericApis"; import { getFormattedStringForDebug, logger } from "./logger"; import createAndSearch from "../config/createAndSearch"; import { addDataToSheet, createBoundaryDataMainSheet, createReadMeSheet, findMapValue, getBoundaryRelationshipData, getConfigurableColumnHeadersFromSchemaForTargetSheet, getLocalizedHeaders, getLocalizedMessagesHandler, getMdmsDataBasedOnCampaignType, modifyBoundaryData, replicateRequest, throwError } from "./genericUtils"; @@ -12,11 +12,14 @@ import { enrichProjectDetailsFromCampaignDetails } from "./transforms/projectTyp import { executeQuery } from "./db"; import { campaignDetailsTransformer, genericResourceTransformer } from "./transforms/searchResponseConstructor"; import { transformAndCreateLocalisation } from "./transforms/localisationMessageConstructor"; -import { campaignStatuses, headingMapping, resourceDataStatuses } from "../config/constants"; +import { campaignStatuses, headingMapping, processTrackStatuses, processTrackTypes, resourceDataStatuses } from "../config/constants"; import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; import { searchProjectTypeCampaignService } from "../service/campaignManageService"; import { validateBoundaryOfResouces } from "../validators/campaignValidators"; import { getExcelWorkbookFromFileURL, getNewExcelWorkbook, lockTargetFields, updateFontNameToRoboto } from "./excelUtils"; +import { areBoundariesSame, callGenerateIfBoundariesDiffer } from "./generateUtils"; +import { createProcessTracks, persistTrack } from "./processTrackUtils"; +import { generateDynamicTargetHeaders, isDynamicTargetTemplateForProjectType, updateTargetColumnsIfDeliveryConditionsDifferForSMC } from "./targetUtils"; const _ = require('lodash'); @@ -220,7 +223,7 @@ function deterMineLastColumnAndEnrichUserDetails(worksheet: any, errorDetailsCol } function adjustRef(worksheet: any, lastColumn: any) { - const range = worksheet.getSheetValues().filter((row: any) => row).length; // Get the number of used rows + const range = getSheetDataFromWorksheet(worksheet).filter((row: any) => row).length; // Get the number of used rows worksheet.views = [ { state: 'frozen', ySplit: 1, topLeftCell: 'A2', activeCell: 'A2' } ]; @@ -475,14 +478,15 @@ async function generateProcessedFileAndPersist(request: any, localizationMap?: { if (request?.body?.ResourceDetails?.action == "create") { persistMessage.ResourceDetails.additionalDetails = {} } - produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); + await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); logger.info(`ResourceDetails to persist : ${request.body.ResourceDetails.type}`); - if (request?.body?.Activities && Array.isArray(request?.body?.Activities && request?.body?.Activities.length > 0)) { + if (request?.body?.Activities && Array.isArray(request?.body?.Activities) && request?.body?.Activities.length > 0) { logger.info("Activities to persist : ") logger.debug(getFormattedStringForDebug(request?.body?.Activities)); logger.info(`Waiting for 2 seconds`); await new Promise(resolve => setTimeout(resolve, 2000)); - produceModifiedMessages(request?.body, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + const activityObject = request?.body?.Activities; + await produceModifiedMessages(activityObject, config.kafka.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); } } @@ -535,10 +539,15 @@ async function enrichAndPersistCampaignWithError(requestBody: any, error: any) { } requestBody.CampaignDetails.additionalDetails = { ...requestBody?.CampaignDetails?.additionalDetails, - error: String((error?.message + " : " + error?.description) || error) + error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) } const topic = config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC - produceModifiedMessages(requestBody, topic); + // wait for 2 seconds + logger.info(`Waiting for 2 seconds to persist errors`); + await new Promise(resolve => setTimeout(resolve, 2000)); + const produceMessage: any = { CampaignDetails: requestBody.CampaignDetails } + await produceModifiedMessages(produceMessage, topic); + await persistTrack(requestBody?.CampaignDetails?.id, processTrackTypes.error, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); delete requestBody.CampaignDetails.campaignDetails } @@ -569,7 +578,10 @@ async function enrichAndPersistCampaignForCreate(request: any, firstPersist: boo } const topic = firstPersist ? config?.kafka?.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC : config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC delete request.body.CampaignDetails.codesTargetMapping - produceModifiedMessages(request?.body, topic); + const produceMessage: any = { + CampaignDetails: request?.body?.CampaignDetails + }; + await produceModifiedMessages(produceMessage, topic); delete request.body.CampaignDetails.campaignDetails } @@ -579,8 +591,16 @@ function enrichInnerCampaignDetails(request: any, updatedInnerCampaignDetails: a updatedInnerCampaignDetails.boundaries = request?.body?.CampaignDetails?.boundaries || [] } + async function enrichAndPersistCampaignForUpdate(request: any, firstPersist: boolean = false) { const action = request?.body?.CampaignDetails?.action; + const existingCampaignDetails = request?.body?.ExistingCampaignDetails; + callGenerateIfBoundariesDiffer(request); + if (existingCampaignDetails) { + if (areBoundariesSame(existingCampaignDetails?.boundaries, request?.body?.CampaignDetails?.boundaries)) { + updateTargetColumnsIfDeliveryConditionsDifferForSMC(request); + } + } const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; var updatedInnerCampaignDetails = {} enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) @@ -607,7 +627,10 @@ async function enrichAndPersistCampaignForUpdate(request: any, firstPersist: boo request.body.CampaignDetails.projectId = request?.body?.CampaignDetails?.projectId || ExistingCampaignDetails?.projectId || null } delete request.body.CampaignDetails.codesTargetMapping - produceModifiedMessages(request?.body, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC); + const producerMessage: any = { + CampaignDetails: request?.body?.CampaignDetails + } + await produceModifiedMessages(producerMessage, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC); delete request.body.ExistingCampaignDetails delete request.body.CampaignDetails.campaignDetails } @@ -644,10 +667,10 @@ async function persistForCampaignProjectMapping(request: any, createResourceDeta enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) requestBody.CampaignDetails = request?.body?.CampaignDetails requestBody.CampaignDetails.campaignDetails = updatedInnerCampaignDetails - requestBody.localizationMap = localizationMap + // requestBody.localizationMap = localizationMap logger.info("Persisting CampaignProjectMapping..."); logger.debug(`CampaignProjectMapping: ${getFormattedStringForDebug(requestBody)}`); - produceModifiedMessages(requestBody, config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC); + await produceModifiedMessages(requestBody, config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC); } } @@ -665,6 +688,9 @@ async function enrichAndPersistProjectCampaignForFirst(request: any, actionInUrl else if (actionInUrl == "update") { await enrichAndPersistCampaignForUpdate(request, firstPersist) } + if (request?.body?.CampaignDetails?.action == "create") { + await createProcessTracks(request.body.CampaignDetails.id) + } } @@ -1286,38 +1312,46 @@ async function getCodesTarget(request: any, localizationMap?: any) { } async function createProject(request: any, actionUrl: any, localizationMap?: any) { - logger.info("Create Projects started for the given Campaign") - var { tenantId, boundaries, projectType, projectId } = request?.body?.CampaignDetails; - if (boundaries && projectType && !projectId) { - const projectTypeResponse = await getMDMSV1Data({}, 'HCM-PROJECT-TYPES', "projectTypes", tenantId); - var Projects: any = enrichProjectDetailsFromCampaignDetails(request?.body?.CampaignDetails, projectTypeResponse?.filter((types: any) => types?.code == projectType)?.[0]); - const projectCreateBody = { - RequestInfo: request?.body?.RequestInfo, - Projects - } - await reorderBoundaries(request, localizationMap) - boundaries = request?.body?.CampaignDetails?.boundaries; - for (const boundary of boundaries) { - Projects[0].address = { tenantId: tenantId, boundary: boundary?.code, boundaryType: boundary?.type } - if (request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent) { - const parent = request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent - await confirmProjectParentCreation(request, request?.body?.boundaryProjectMapping?.[parent]?.projectId) - Projects[0].parent = request?.body?.boundaryProjectMapping?.[parent]?.projectId - } - else { - Projects[0].parent = null + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.inprogress); + try { + logger.info("Create Projects started for the given Campaign") + var { tenantId, boundaries, projectType, projectId } = request?.body?.CampaignDetails; + if (boundaries && projectType && !projectId) { + const projectTypeResponse = await getMDMSV1Data({}, 'HCM-PROJECT-TYPES', "projectTypes", tenantId); + var Projects: any = enrichProjectDetailsFromCampaignDetails(request?.body?.CampaignDetails, projectTypeResponse?.filter((types: any) => types?.code == projectType)?.[0]); + const projectCreateBody = { + RequestInfo: request?.body?.RequestInfo, + Projects } - Projects[0].referenceID = request?.body?.CampaignDetails?.id - Projects[0].targets = [ - { - beneficiaryType: request?.body?.CampaignDetails?.additionalDetails?.beneficiaryType, - totalNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code], - targetNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code] + await reorderBoundaries(request, localizationMap) + boundaries = request?.body?.CampaignDetails?.boundaries; + for (const boundary of boundaries) { + Projects[0].address = { tenantId: tenantId, boundary: boundary?.code, boundaryType: boundary?.type } + if (request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent) { + const parent = request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent + await confirmProjectParentCreation(request, request?.body?.boundaryProjectMapping?.[parent]?.projectId) + Projects[0].parent = request?.body?.boundaryProjectMapping?.[parent]?.projectId } - ] - await projectCreate(projectCreateBody, request) + else { + Projects[0].parent = null + } + Projects[0].referenceID = request?.body?.CampaignDetails?.id + Projects[0].targets = [ + { + beneficiaryType: request?.body?.CampaignDetails?.additionalDetails?.beneficiaryType, + totalNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code], + targetNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code] + } + ] + await projectCreate(projectCreateBody, request) + } } + } catch (error: any) { + console.log(error) + await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) } + await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.completed); } @@ -1325,6 +1359,7 @@ async function processAfterPersist(request: any, actionInUrl: any) { try { const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.CampaignDetails?.tenantId); if (request?.body?.CampaignDetails?.action == "create") { + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.validation, processTrackStatuses.completed); await createProjectCampaignResourcData(request); await createProject(request, actionInUrl, localizationMap) await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) @@ -1336,7 +1371,7 @@ async function processAfterPersist(request: any, actionInUrl: any) { } catch (error: any) { console.log(error) logger.error(error) - enrichAndPersistCampaignWithError(request?.body, error) + await enrichAndPersistCampaignWithError(request?.body, error) } } @@ -1372,13 +1407,19 @@ async function appendSheetsToWorkbook(request: any, boundaryData: any[], differe const localisedHeading = getLocalizedName(headingInSheet, localizationMap); await createReadMeSheet(request, workbook, localisedHeading, localizationMap); const [mainSheetData, uniqueDistrictsForMainSheet, districtLevelRowBoundaryCodeMap] = createBoundaryDataMainSheet(request, boundaryData, differentTabsBasedOnLevel, hierarchy, localizationMap) - const mainSheet = workbook.addWorksheet(getLocalizedName(getBoundaryTabName(), localizationMap)); - const columnWidths = Array(12).fill(30); - mainSheet.columns = columnWidths.map(width => ({ width })); - // mainSheetData.forEach(row => mainSheet.addRow(row)); - addDataToSheet(mainSheet, mainSheetData, 'F3842D', 30, false, true); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + if (!(isSourceMicroplan)) { + const mainSheet = workbook.addWorksheet(getLocalizedName(getBoundaryTabName(), localizationMap)); + const columnWidths = Array(12).fill(30); + mainSheet.columns = columnWidths.map(width => ({ width })); + // mainSheetData.forEach(row => mainSheet.addRow(row)); + addDataToSheet(mainSheet, mainSheetData, 'F3842D', 30, false, true); + mainSheet.state = 'hidden'; + } logger.info("appending different districts tab in the sheet started") - await appendDistricts(request, workbook, uniqueDistrictsForMainSheet, differentTabsBasedOnLevel, boundaryData, localizationMap, districtLevelRowBoundaryCodeMap, hierarchy); + await appendDistricts(request, workbook, uniqueDistrictsForMainSheet, differentTabsBasedOnLevel, boundaryData, localizationMap, districtLevelRowBoundaryCodeMap, hierarchy, campaignObject); logger.info("Sheet with different tabs generated successfully"); return workbook; } catch (error) { @@ -1388,8 +1429,8 @@ async function appendSheetsToWorkbook(request: any, boundaryData: any[], differe } -async function appendDistricts(request: any, workbook: any, uniqueDistrictsForMainSheet: any, differentTabsBasedOnLevel: any, boundaryData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, hierarchy: any) { - const configurableColumnHeadersFromSchemaForTargetSheet = await getConfigurableColumnHeadersFromSchemaForTargetSheet(request, hierarchy, boundaryData, differentTabsBasedOnLevel, localizationMap); +async function appendDistricts(request: any, workbook: any, uniqueDistrictsForMainSheet: any, differentTabsBasedOnLevel: any, boundaryData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, hierarchy: any, campaignObject: any) { + const configurableColumnHeadersFromSchemaForTargetSheet = await getConfigurableColumnHeadersFromSchemaForTargetSheet(request, hierarchy, boundaryData, differentTabsBasedOnLevel, campaignObject, localizationMap); for (const uniqueData of uniqueDistrictsForMainSheet) { const uniqueDataFromLevelForDifferentTabs = uniqueData.slice(uniqueData.lastIndexOf('#') + 1); logger.info(`generating the boundary data for ${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel}`) @@ -1404,19 +1445,24 @@ async function appendDistricts(request: any, workbook: any, uniqueDistrictsForMa } newSheetData.push(rowData); } - await createNewSheet(request, workbook, newSheetData, uniqueData, localizationMap, districtLevelRowBoundaryCodeMap, configurableColumnHeadersFromSchemaForTargetSheet); + await createNewSheet(request, workbook, newSheetData, uniqueData, localizationMap, districtLevelRowBoundaryCodeMap, configurableColumnHeadersFromSchemaForTargetSheet, campaignObject); logger.info(`${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel} boundary data generation completed`) } } } - -async function createNewSheet(request: any, workbook: any, newSheetData: any, uniqueData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, localizedHeaders: any) { +async function createNewSheet(request: any, workbook: any, newSheetData: any, uniqueData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, localizedHeaders: any, campaignObject: any) { const newSheet = workbook.addWorksheet(getLocalizedName(districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap)); addDataToSheet(newSheet, newSheetData, 'F3842D', 40); + let columnsNotToBeFreezed: any; const boundaryCodeColumnIndex = localizedHeaders.findIndex((header: any) => header === getLocalizedName(config?.boundary?.boundaryCode, localizationMap)); - const mdmsResponse = await getMdmsDataBasedOnCampaignType(request, localizationMap) - const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0) { + columnsNotToBeFreezed = localizedHeaders.slice(boundaryCodeColumnIndex + 1); + } + else { + const mdmsResponse = await getMdmsDataBasedOnCampaignType(request, localizationMap) + columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + } const localizedColumnsNotToBeFreezed = getLocalizedHeaders(columnsNotToBeFreezed, localizationMap); lockTargetFields(newSheet, localizedColumnsNotToBeFreezed, boundaryCodeColumnIndex); } @@ -1575,10 +1621,12 @@ const autoGenerateBoundaryCodes = async (request: any, localizationMap?: any) => const modifiedBoundaryData = modifyBoundaryDataHeaders(updatedBoundaryData, hierarchy, localizationMap); const [withBoundaryCode, withoutBoundaryCode] = modifyBoundaryData(modifiedBoundaryData, localizationMap); const { mappingMap, countMap } = getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode); - const childParentMap = getChildParentMap(withoutBoundaryCode); + const childParentMap = getChildParentMap([...withBoundaryCode, ...withoutBoundaryCode]); const boundaryMap = await getAutoGeneratedBoundaryCodesHandler(withoutBoundaryCode, childParentMap, mappingMap, countMap, request); logger.info("Boundary Code Auto Generation Completed"); await createBoundaryEntities(request, boundaryMap); + logger.info("waiting for 2 secs to persist the boundary entities before creating boundary relationship") + await new Promise(resolve => setTimeout(resolve, 2000)); const modifiedChildParentMap = modifyChildParentMap(childParentMap, boundaryMap); await createBoundaryRelationship(request, boundaryMap, modifiedChildParentMap); const boundaryDataForSheet = addBoundaryCodeToData(withBoundaryCode, withoutBoundaryCode, boundaryMap); @@ -1738,8 +1786,10 @@ function getFiltersFromCampaignSearchResponse(responseFromCampaignSearch: any) { const getConfigurableColumnHeadersBasedOnCampaignType = async (request: any, localizationMap?: any) => { try { const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; - + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + let campaignType = campaignObject?.projectType; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + campaignType = (isSourceMicroplan) ? `${config?.prefixForMicroplanCampaigns}-${campaignType}` : campaignType; const mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) if (!mdmsResponse || mdmsResponse?.columns.length === 0) { logger.error(`Campaign Type ${campaignType} has not any columns configured in schema`) @@ -1763,22 +1813,24 @@ const getConfigurableColumnHeadersBasedOnCampaignType = async (request: any, loc } -async function getFinalValidHeadersForTargetSheetAsPerCampaignType(request: any, hierarchy: any[], localizationMap?: any) { +async function getFinalValidHeadersForTargetSheetAsPerCampaignType(request: any, hierarchy: any[], differentTabsBasedOnLevel: any, localizationMap?: any) { const modifiedHierarchy = hierarchy.map(ele => `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase()); const localizedHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); - const index = localizedHierarchy.indexOf(getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)); + const index = localizedHierarchy.indexOf(getLocalizedName(differentTabsBasedOnLevel, localizationMap)); const expectedHeadersForTargetSheetUptoHierarchy = index !== -1 ? localizedHierarchy.slice(index) : throwError("COMMON", 400, "VALIDATION_ERROR", `${getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)} level not present in the hierarchy`); - const columnFromSchemaOfTargetTemplate = await getConfigurableColumnHeadersBasedOnCampaignType(request); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + const columnFromSchemaOfTargetTemplate = await generateDynamicTargetHeaders(request, campaignObject, localizationMap); const localizedcolumnFromSchemaOfTargetTemplate = getLocalizedHeaders(columnFromSchemaOfTargetTemplate, localizationMap) - const expectedHeadersForTargetSheet = [...expectedHeadersForTargetSheetUptoHierarchy, ...localizedcolumnFromSchemaOfTargetTemplate]; + const expectedHeadersForTargetSheet = [...expectedHeadersForTargetSheetUptoHierarchy, getLocalizedName(config?.boundary?.boundaryCode, localizationMap), ...localizedcolumnFromSchemaOfTargetTemplate]; return expectedHeadersForTargetSheet; } async function getDifferentTabGeneratedBasedOnConfig(request: any, boundaryDataGeneratedBeforeDifferentTabSeparation: any, localizationMap?: any) { - // assigning fileStoreId of a single district tab if criteria for multiple tabs are not met var boundaryDataGeneratedAfterDifferentTabSeparation: any = boundaryDataGeneratedBeforeDifferentTabSeparation; const boundaryData = await getBoundaryDataAfterGeneration(boundaryDataGeneratedBeforeDifferentTabSeparation, request, localizationMap); - const differentTabsBasedOnLevel = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); + let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request); + differentTabsBasedOnLevel = getLocalizedName(`${request?.query?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), localizationMap); logger.info(`Boundaries are seperated based on hierarchy type ${differentTabsBasedOnLevel}`) const isKeyOfThatTypePresent = boundaryData.some((data: any) => data.hasOwnProperty(differentTabsBasedOnLevel)); const boundaryTypeOnWhichWeSplit = boundaryData.filter((data: any) => data[differentTabsBasedOnLevel]); @@ -1789,6 +1841,19 @@ async function getDifferentTabGeneratedBasedOnConfig(request: any, boundaryDataG return boundaryDataGeneratedAfterDifferentTabSeparation; } +async function getBoundaryOnWhichWeSplit(request: any) { + const mdmsResponse = await getMDMSV1Data(request, config?.values?.moduleName, config?.masterNameForSplitBoundariesOn, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const hierarchyTypeFromCampaignResponseObject = responseFromCampaignSearch?.CampaignDetails?.[0].hierarchyType; + return mdmsResponse.filter((item: any) => item.hierarchy == hierarchyTypeFromCampaignResponseObject).map((item: any) => item.splitBoundariesOn); +} + + +function checkIfSourceIsMicroplan(objectWithAdditionalDetails: any): boolean { + return objectWithAdditionalDetails?.additionalDetails?.source === 'microplan'; +} + + @@ -1821,5 +1886,7 @@ export { getFiltersFromCampaignSearchResponse, getConfigurableColumnHeadersBasedOnCampaignType, getFinalValidHeadersForTargetSheetAsPerCampaignType, - getDifferentTabGeneratedBasedOnConfig + getDifferentTabGeneratedBasedOnConfig, + checkIfSourceIsMicroplan, + getBoundaryOnWhichWeSplit } diff --git a/health-services/project-factory/src/server/utils/excelUtils.ts b/health-services/project-factory/src/server/utils/excelUtils.ts index 8624ed7b977..8f7a0acc614 100644 --- a/health-services/project-factory/src/server/utils/excelUtils.ts +++ b/health-services/project-factory/src/server/utils/excelUtils.ts @@ -71,8 +71,8 @@ function updateFontNameToRoboto(worksheet: ExcelJS.Worksheet) { function formatWorksheet(worksheet: any, datas: any, headerSet: any) { // Add empty rows after the main header - worksheet.addRow([]); - worksheet.addRow([]); + // worksheet.addRow([]); + // worksheet.addRow([]); worksheet.addRow([]); // Add the data rows with text wrapping @@ -136,46 +136,70 @@ function performFreezeWholeSheet(sheet: any) { sheet.protect('passwordhere', { selectLockedCells: true }); } -function addDataToSheet(sheet: any, sheetData: any, firstRowColor: any = '93C47D', columnWidth = 40, frozeCells = false, frozeWholeSheet = false) { +// Function to add data to the sheet +function addDataToSheet(sheet: any, sheetData: any, firstRowColor: string = '93C47D', columnWidth: number = 40, frozeCells: boolean = false, frozeWholeSheet: boolean = false) { sheetData?.forEach((row: any, index: number) => { const worksheetRow = sheet.addRow(row); - // Apply fill color to each cell in the first row and make cells bold if (index === 0) { - worksheetRow.eachCell((cell: any, colNumber: number) => { - // Set cell fill color - cell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: firstRowColor } // Green color - }; - - // Set font to bold - cell.font = { bold: true }; + formatFirstRow(worksheetRow, sheet, firstRowColor, columnWidth, frozeCells); + } else { + formatOtherRows(worksheetRow, frozeCells); + } + }); + + finalizeSheet(sheet, frozeCells, frozeWholeSheet); +} + +// Function to format the first row +function formatFirstRow(row: any, sheet: any, firstRowColor: string, columnWidth: number, frozeCells: boolean) { + row.eachCell((cell: any, colNumber: number) => { + setFirstRowCellStyles(cell, firstRowColor, frozeCells); + adjustColumnWidth(sheet, colNumber, columnWidth); + adjustRowHeight(row, cell, columnWidth); + }); +} + +// Function to set styles for the first row's cells +function setFirstRowCellStyles(cell: any, firstRowColor: string, frozeCells: boolean) { + cell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: firstRowColor } + }; + + cell.font = { bold: true }; - // Enable text wrapping - cell.alignment = { wrapText: true }; + if (frozeCells) { + cell.protection = { locked: true }; + } - // Optionally lock the cell - if (frozeCells) { - cell.protection = { locked: true }; - } + cell.alignment = { vertical: 'top', horizontal: 'left', wrapText: true }; +} - // Update column width based on the length of the cell's text - const currentWidth = sheet.getColumn(colNumber).width || columnWidth; // Default width or current width - const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding - sheet.getColumn(colNumber).width = newWidth; - }); +// Function to adjust column width +function adjustColumnWidth(sheet: any, colNumber: number, columnWidth: number) { + sheet.getColumn(colNumber).width = columnWidth; +} +// Function to adjust row height based on content +function adjustRowHeight(row: any, cell: any, columnWidth: number) { + const text = cell.value ? cell.value.toString() : ''; + const lines = Math.ceil(text.length / (columnWidth - 2)); // Approximate number of lines + row.height = Math.max(row.height ?? 0, lines * 15); +} + +// Function to format cells in other rows +function formatOtherRows(row: any, frozeCells: boolean) { + row.eachCell((cell: any) => { + if (frozeCells) { + cell.protection = { locked: true }; } - worksheetRow.eachCell((cell: any) => { - if (frozeCells) { - cell.protection = { locked: true }; - } - }); }); +} - // Protect the entire sheet to enable cell protection settings +// Function to finalize the sheet settings +function finalizeSheet(sheet: any, frozeCells: boolean, frozeWholeSheet: boolean) { if (frozeCells) { performUnfreezeCells(sheet); } @@ -183,9 +207,13 @@ function addDataToSheet(sheet: any, sheetData: any, firstRowColor: any = '93C47D performFreezeWholeSheet(sheet); } updateFontNameToRoboto(sheet); + sheet.views = [{ state: 'frozen', ySplit: 1, zoomScale: 110 }]; } + + + function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCodeColumnIndex: any) { // Make every cell locked by default newSheet.eachRow((row: any) => { diff --git a/health-services/project-factory/src/server/utils/generateUtils.ts b/health-services/project-factory/src/server/utils/generateUtils.ts new file mode 100644 index 00000000000..a8a03e65d7c --- /dev/null +++ b/health-services/project-factory/src/server/utils/generateUtils.ts @@ -0,0 +1,85 @@ +import { getLocalizedMessagesHandler, processGenerate, replicateRequest, throwError } from "./genericUtils"; +import _ from 'lodash'; +import { logger } from "./logger"; +import { getBoundarySheetData } from "../api/genericApis"; +import { getLocalisationModuleName } from "./localisationUtils"; + +// Now you can use Lodash functions with the "_" prefix, e.g., _.isEqual(), _.sortBy(), etc. +function extractProperties(obj: any) { + return { + code: obj.code || null, + includeAllChildren: obj.includeAllChildren || null, + isRoot: obj.isRoot || null + }; +} + +function areBoundariesSame(existingBoundaries: any, currentBoundaries: any) { + if (!existingBoundaries || !currentBoundaries) return false; + if (existingBoundaries.length !== currentBoundaries.length) return false; + const existingSetOfBoundaries = new Set(existingBoundaries.map((exboundary: any) => JSON.stringify(extractProperties(exboundary)))); + const currentSetOfBoundaries = new Set(currentBoundaries.map((currboundary: any) => JSON.stringify(extractProperties(currboundary)))); + return _.isEqual(existingSetOfBoundaries, currentSetOfBoundaries); +} + +async function callGenerateIfBoundariesDiffer(request: any) { + try { + const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + if (ExistingCampaignDetails) { + if (!areBoundariesSame(ExistingCampaignDetails?.boundaries, request?.body?.CampaignDetails?.boundaries)) { + logger.info("Boundaries differ, generating new resources"); + + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, + Filters: { + boundaries: request?.body?.CampaignDetails?.boundaries + } + }; + + const { query } = request; + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + forceUpdate: 'true', + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + campaignId: request?.body?.CampaignDetails?.id + }; + + const newParamsBoundary = { ...query, ...params, type: "boundary" }; + const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); + await callGenerate(newRequestBoundary, "boundary"); + + const newParamsFacilityWithBoundary = { ...query, ...params, type: "facilityWithBoundary" }; + const newRequestFacilityWithBoundary = replicateRequest(request, newRequestBody, newParamsFacilityWithBoundary); + await callGenerate(newRequestFacilityWithBoundary, "facilityWithBoundary"); + + const newParamsUserWithBoundary = { ...query, ...params, type: "userWithBoundary" }; + const newRequestUserWithBoundary = replicateRequest(request, newRequestBody, newParamsUserWithBoundary); + await callGenerate(newRequestUserWithBoundary, "userWithBoundary"); + } + } + } catch (error: any) { + logger.error(error); + throwError("COMMON", 400, "GENERATE_ERROR", `Error while generating user/facility/boundary: ${error.message}`); + } +} + +async function callGenerate(request: any, type: any, enableCaching = false) { + logger.info(`calling generate api for type ${type}`); + if (type === "facilityWithBoundary" || type == "userWithBoundary") { + const { hierarchyType } = request.query; + const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler( + request, + request.query.tenantId, + getLocalisationModuleName(hierarchyType) + ); + const localizationMapModule = await getLocalizedMessagesHandler(request, request.query.tenantId); + const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; + const filteredBoundary = await getBoundarySheetData(request, localizationMap); + await processGenerate(request, enableCaching, filteredBoundary); + } else { + await processGenerate(request, enableCaching); + } +} + + + +export { callGenerateIfBoundariesDiffer, callGenerate, areBoundariesSame } diff --git a/health-services/project-factory/src/server/utils/genericUtils.ts b/health-services/project-factory/src/server/utils/genericUtils.ts index fa3c194b8ca..df6f5ec8bfb 100644 --- a/health-services/project-factory/src/server/utils/genericUtils.ts +++ b/health-services/project-factory/src/server/utils/genericUtils.ts @@ -2,20 +2,21 @@ import { NextFunction, Request, Response } from "express"; import { httpRequest, defaultheader } from "./request"; import config, { getErrorCodes } from "../config/index"; import { v4 as uuidv4 } from 'uuid'; -import { produceModifiedMessages } from "../kafka/Listener"; +import { produceModifiedMessages } from "../kafka/Producer"; import { generateHierarchyList, getAllFacilities, getCampaignSearchResponse, getHierarchy } from "../api/campaignApis"; import { getBoundarySheetData, getSheetData, createAndUploadFile, createExcelSheet, getTargetSheetData, callMdmsData, callMdmsTypeSchema } from "../api/genericApis"; import { logger } from "./logger"; -import { getConfigurableColumnHeadersBasedOnCampaignType, getDifferentTabGeneratedBasedOnConfig, getLocalizedName } from "./campaignUtils"; +import { checkIfSourceIsMicroplan, getConfigurableColumnHeadersBasedOnCampaignType, getDifferentTabGeneratedBasedOnConfig, getLocalizedName } from "./campaignUtils"; import Localisation from "../controllers/localisationController/localisation.controller"; import { executeQuery } from "./db"; import { generatedResourceTransformer } from "./transforms/searchResponseConstructor"; import { generatedResourceStatuses, headingMapping, resourceDataStatuses } from "../config/constants"; -import { getLocaleFromRequest, getLocalisationModuleName } from "./localisationUtils"; +import { getLocaleFromRequest, getLocaleFromRequestInfo, getLocalisationModuleName } from "./localisationUtils"; import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; import { getBoundaryDataService } from "../service/dataManageService"; import { addDataToSheet, formatWorksheet, getNewExcelWorkbook, updateFontNameToRoboto } from "./excelUtils"; import createAndSearch from "../config/createAndSearch"; +import { generateDynamicTargetHeaders } from "./targetUtils"; const NodeCache = require("node-cache"); const updateGeneratedResourceTopic = config?.kafka?.KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC; @@ -51,6 +52,12 @@ const throwErrorViaRequest = (message: any = "Internal Server Error") => { } }; +function shutdownGracefully() { + logger.info('Shutting down gracefully...'); + // Perform any cleanup tasks here, like closing database connections + process.exit(1); // Exit with a non-zero code to indicate an error +} + function capitalizeFirstLetter(str: string | undefined) { if (!str) return str; return str.charAt(0).toUpperCase() + str.slice(1); @@ -240,27 +247,47 @@ async function generateActivityMessage(tenantId: any, requestBody: any, requestP /* Fetches data from the database */ async function searchGeneratedResources(request: any) { try { - const { type } = request.query; - const { tenantId, hierarchyType } = request.query; - const status = generatedResourceStatuses.completed; - let queryResult: any; - let queryString: string; + const { type, tenantId, hierarchyType, id, status, campaignId } = request.query; + let queryString = `SELECT * FROM ${config?.DB_CONFIG.DB_GENERATED_RESOURCE_DETAILS_TABLE_NAME} WHERE `; + let queryConditions: string[] = []; let queryValues: any[] = []; + if (id) { + queryConditions.push(`id = $${queryValues.length + 1}`); + queryValues.push(id); + } + if (type) { + queryConditions.push(`type = $${queryValues.length + 1}`); + queryValues.push(type); + } - queryString = `SELECT * FROM ${config?.DB_CONFIG.DB_GENERATED_RESOURCE_DETAILS_TABLE_NAME} WHERE `; - // query for download with id - if (request?.query?.id) { - queryString += "id = $1 AND type = $2 AND hierarchytype = $3 AND tenantid = $4 "; - queryValues = [request.query.id, type, hierarchyType, tenantId]; + if (hierarchyType) { + queryConditions.push(`hierarchyType = $${queryValues.length + 1}`); + queryValues.push(hierarchyType); } - else { - queryString += "type = $1 AND hierarchytype = $2 AND tenantid = $3 AND status =$4 "; - queryValues = [type, hierarchyType, tenantId, status]; + if (tenantId) { + queryConditions.push(`tenantId = $${queryValues.length + 1}`); + queryValues.push(tenantId); + } + if (campaignId) { + queryConditions.push(`campaignId = $${queryValues.length + 1}`); + queryValues.push(campaignId); } - queryResult = await executeQuery(queryString, queryValues); + if (status) { + const statusArray = status.split(',').map((s: any) => s.trim()); + const statusConditions = statusArray.map((_: any, index: any) => `status = $${queryValues.length + index + 1}`); + queryConditions.push(`(${statusConditions.join(' OR ')})`); + queryValues.push(...statusArray); + } + + queryString += queryConditions.join(" AND "); + + // Add sorting and limiting + queryString += " ORDER BY createdTime DESC OFFSET 0 LIMIT 1"; + + const queryResult = await executeQuery(queryString, queryValues); return generatedResourceTransformer(queryResult?.rows); - } - catch (error: any) { + } catch (error: any) { + console.log(error) logger.error(`Error fetching data from the database: ${error.message}`); throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", error?.message); return null; // Return null in case of an error @@ -300,7 +327,8 @@ async function generateNewRequestObject(request: any) { lastModifiedBy: request?.body?.RequestInfo?.userInfo.uuid, }, additionalDetails: additionalDetails, - count: null + count: null, + campaignId: request?.query?.campaignId }; return [newEntry]; } @@ -333,20 +361,20 @@ async function getFinalUpdatedResponse(result: any, responseData: any, request: -async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResource: any, request: any) { +async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResource: any, request: any, enableCaching = false, filteredBoundary?: any) { try { const { type, hierarchyType } = request?.query; generatedResource = { generatedResource: newEntryResponse } // send message to create toppic logger.info(`processing the generate request for type ${type}`) - produceModifiedMessages(generatedResource, createGeneratedResourceTopic); + await produceModifiedMessages(generatedResource, createGeneratedResourceTopic); const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; if (type === 'boundary') { // get boundary data from boundary relationship search api logger.info("Generating Boundary Data") - const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request); + const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request, enableCaching); logger.info(`Boundary data generated successfully: ${JSON.stringify(boundaryDataSheetGeneratedBeforeDifferentTabSeparation)}`); // get boundary sheet data after being generated logger.info("generating different tabs logic ") @@ -355,18 +383,19 @@ async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResour const finalResponse = await getFinalUpdatedResponse(boundaryDataSheetGeneratedAfterDifferentTabSeparation, newEntryResponse, request); const generatedResourceNew: any = { generatedResource: finalResponse } // send to update topic - produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); request.body.generatedResource = finalResponse; } else if (type == "facilityWithBoundary" || type == 'userWithBoundary') { - await processGenerateRequest(request, localizationMap); + await processGenerateRequest(request, localizationMap, filteredBoundary); const finalResponse = await getFinalUpdatedResponse(request?.body?.fileDetails, newEntryResponse, request); const generatedResourceNew: any = { generatedResource: finalResponse } - produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); request.body.generatedResource = finalResponse; } } catch (error: any) { - handleGenerateError(newEntryResponse, generatedResource, error); + console.log(error) + await handleGenerateError(newEntryResponse, generatedResource, error); } } @@ -420,13 +449,40 @@ function correctParentValues(campaignDetails: any) { return campaignDetails; } +function setDropdownFromSchema(request: any, schema: any, localizationMap?: { [key: string]: string }) { + const dropdowns = Object.entries(schema.properties) + .filter(([key, value]: any) => Array.isArray(value.enum) && value.enum.length > 0) + .reduce((result: any, [key, value]: any) => { + // Transform the key using localisedValue function + const newKey: any = getLocalizedName(key, localizationMap); + result[newKey] = value.enum; + return result; + }, {}); + logger.info(`dropdowns to set ${JSON.stringify(dropdowns)}`) + request.body.dropdowns = dropdowns; +} + async function createFacilitySheet(request: any, allFacilities: any[], localizationMap?: { [key: string]: string }) { const tenantId = request?.query?.tenantId; - const schema = await callMdmsTypeSchema(request, tenantId, "facility"); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const isSourceMicroplan = checkIfSourceIsMicroplan(responseFromCampaignSearch?.CampaignDetails?.[0]); + let schema; + if (isSourceMicroplan) { + schema = await callMdmsTypeSchema(request, tenantId, "facility", "microplan"); + } else { + schema = await callMdmsTypeSchema(request, tenantId, "facility", "all"); + } const keys = schema?.columns; + setDropdownFromSchema(request, schema, localizationMap); const headers = ["HCM_ADMIN_CONSOLE_FACILITY_CODE", ...keys] - const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + let localizedHeaders; + if (isSourceMicroplan) { + localizedHeaders = getLocalizedHeadersForMicroplan(responseFromCampaignSearch, headers, localizationMap); + } + else { + localizedHeaders = getLocalizedHeaders(headers, localizationMap); + } const facilities = allFacilities.map((facility: any) => { return [ facility?.id, @@ -471,13 +527,15 @@ async function createReadMeSheet(request: any, workbook: any, mainHeader: any, l const headerSet = new Set(); - const datas = readMeConfig.texts.flatMap((text: any) => { - const descriptions = text.descriptions.map((description: any) => { - return getLocalizedName(description.text, localizationMap); + const datas = readMeConfig.texts + .filter((text: any) => text?.inSheet) // Filter out texts with inSheet set to false + .flatMap((text: any) => { + const descriptions = text.descriptions.map((description: any) => { + return getLocalizedName(description.text, localizationMap); + }); + headerSet.add(getLocalizedName(text.header, localizationMap)); + return [getLocalizedName(text.header, localizationMap), ...descriptions, ""]; }); - headerSet.add(getLocalizedName(text.header, localizationMap)); - return [getLocalizedName(text.header, localizationMap), ...descriptions, "", "", "", ""]; - }); // Create the worksheet and add the main header const worksheet = workbook.addWorksheet(getLocalizedName("HCM_README_SHEETNAME", localizationMap)); @@ -525,6 +583,21 @@ function getLocalizedHeaders(headers: any, localizationMap?: { [key: string]: st return messages; } +function getLocalizedHeadersForMicroplan(responseFromCampaignSearch: any, headers: any, localizationMap?: { [key: string]: string }) { + + const projectType = responseFromCampaignSearch?.CampaignDetails?.[0]?.projectType; + + headers = headers.map((header: string) => { + if (header === 'HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN') { + return `${header}_${projectType}`; + } + return header; + }); + + const messages = headers.map((header: any) => (localizationMap ? localizationMap[header] || header : header)); + return messages; +} + function modifyRequestForLocalisation(request: any, tenantId: string) { @@ -594,6 +667,7 @@ async function createFacilityAndBoundaryFile(facilitySheetData: any, boundaryShe addDataToSheet(facilitySheet, facilitySheetData, undefined, undefined, true); hideUniqueIdentifierColumn(facilitySheet, createAndSearch?.["facility"]?.uniqueIdentifierColumn); changeFirstRowColumnColour(facilitySheet, 'E06666'); + await handledropdownthings(facilitySheet, request.body?.dropdowns); // Add boundary sheet to the workbook const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); @@ -605,8 +679,41 @@ async function createFacilityAndBoundaryFile(facilitySheetData: any, boundaryShe request.body.fileDetails = fileDetails; } - -// Helper function to add data to a sheet +async function handledropdownthings(facilitySheet: any, dropdowns: any) { + let dropdownColumnIndex = -1; + if (dropdowns) { + for (const key of Object.keys(dropdowns)) { + if (dropdowns[key]) { + // Iterate through each row to find the column index of "Boundary Code (Mandatory)" + await facilitySheet.eachRow({ includeEmpty: true }, (row: any) => { + row.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { + if (cell.value === key) { + dropdownColumnIndex = colNumber; + } + }); + }); + + // If dropdown column index is found, set multi-select dropdown for subsequent rows + if (dropdownColumnIndex !== -1) { + facilitySheet.getColumn(dropdownColumnIndex).eachCell({ includeEmpty: true }, (cell: any, rowNumber: any) => { + if (rowNumber > 1) { + // Set dropdown list with no typing allowed + cell.dataValidation = { + type: 'list', + formulae: [`"${dropdowns[key].join(',')}"`], + showDropDown: true, // Ensures dropdown is visible + error: 'Please select a value from the dropdown list.', + errorStyle: 'stop', // Prevents any input not in the list + showErrorMessage: true, // Ensures error message is shown + errorTitle: 'Invalid Entry' + }; + } + }); + } + } + } + } +} @@ -623,6 +730,7 @@ async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: const userSheet = workbook.addWorksheet(localizedUserTab); addDataToSheet(userSheet, userSheetData, undefined, undefined, true); + await handledropdownthings(userSheet, request.body?.dropdowns); // Add boundary sheet to the workbook const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap) const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); @@ -633,7 +741,7 @@ async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: } -async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }) { +async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { // Get facility and boundary data logger.info("Generating facilities started"); const allFacilities = await getAllFacilities(tenantId, request.body); @@ -641,38 +749,49 @@ async function generateFacilityAndBoundarySheet(tenantId: string, request: any, logger.info(`Facilities generation completed and found ${allFacilities?.length} facilities`); const facilitySheetData: any = await createFacilitySheet(request, allFacilities, localizationMap); // request.body.Filters = { tenantId: tenantId, hierarchyType: request?.query?.hierarchyType, includeChildren: true } - const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); - await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap); + if (filteredBoundary && filteredBoundary.length > 0) { + await createFacilityAndBoundaryFile(facilitySheetData, filteredBoundary, request, localizationMap); + } + else { + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap); + } } -async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }) { +async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { const userData: any[] = []; const tenantId = request?.query?.tenantId; const schema = await callMdmsTypeSchema(request, tenantId, "user"); + setDropdownFromSchema(request, schema, localizationMap); const headers = schema?.columns; const localizedHeaders = getLocalizedHeaders(headers, localizationMap); // const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); logger.info("Generated an empty user template"); const userSheetData = await createExcelSheet(userData, localizedHeaders); - const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); - await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, localizationMap); + if (filteredBoundary && filteredBoundary.length > 0) { + await createUserAndBoundaryFile(userSheetData, filteredBoundary, request, localizationMap); + } + else { + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, localizationMap); + } } -async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }) { +async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { const { type, tenantId } = request.query if (type == "facilityWithBoundary") { - await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap); + await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap, filteredBoundary); } if (type == "userWithBoundary") { - await generateUserAndBoundarySheet(request, localizationMap); + await generateUserAndBoundarySheet(request, localizationMap, filteredBoundary); } } -async function processGenerateForNew(request: any, generatedResource: any, newEntryResponse: any) { +async function processGenerateForNew(request: any, generatedResource: any, newEntryResponse: any, enableCaching = false, filteredBoundary?: any) { request.body.generatedResource = newEntryResponse; - fullProcessFlowForNewEntry(newEntryResponse, generatedResource, request); + await fullProcessFlowForNewEntry(newEntryResponse, generatedResource, request, enableCaching, filteredBoundary); return request.body.generatedResource; } -function handleGenerateError(newEntryResponse: any, generatedResource: any, error: any) { +async function handleGenerateError(newEntryResponse: any, generatedResource: any, error: any) { newEntryResponse.map((item: any) => { item.status = generatedResourceStatuses.failed, item.additionalDetails = { ...item.additionalDetails, error: { @@ -685,21 +804,21 @@ function handleGenerateError(newEntryResponse: any, generatedResource: any, erro }) generatedResource = { generatedResource: newEntryResponse }; logger.error(String(error)); - produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); + await produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); } -async function updateAndPersistGenerateRequest(newEntryResponse: any, oldEntryResponse: any, responseData: any, request: any) { +async function updateAndPersistGenerateRequest(newEntryResponse: any, oldEntryResponse: any, responseData: any, request: any, enableCaching = false, filteredBoundary?: any) { const { forceUpdate } = request.query; const forceUpdateBool: boolean = forceUpdate === 'true'; let generatedResource: any; if (forceUpdateBool && responseData.length > 0) { generatedResource = { generatedResource: oldEntryResponse }; // send message to update topic - produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); + await produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); request.body.generatedResource = oldEntryResponse; } if (responseData.length === 0 || forceUpdateBool) { - processGenerateForNew(request, generatedResource, newEntryResponse) + processGenerateForNew(request, generatedResource, newEntryResponse, enableCaching, filteredBoundary) } else { request.body.generatedResource = responseData @@ -708,7 +827,7 @@ async function updateAndPersistGenerateRequest(newEntryResponse: any, oldEntryRe /* */ -async function processGenerate(request: any) { +async function processGenerate(request: any, enableCaching = false, filteredBoundary?: any) { // fetch the data from db to check any request already exists const responseData = await searchGeneratedResources(request); // modify response from db @@ -718,7 +837,7 @@ async function processGenerate(request: any) { // make old data status as expired const oldEntryResponse = await updateExistingResourceExpired(modifiedResponse, request); // generate data - await updateAndPersistGenerateRequest(newEntryResponse, oldEntryResponse, responseData, request); + await updateAndPersistGenerateRequest(newEntryResponse, oldEntryResponse, responseData, request, enableCaching, filteredBoundary); } /* TODO add comments @nitish-egov @@ -739,8 +858,11 @@ async function enrichResourceDetails(request: any) { lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, lastModifiedTime: Date.now() } + if (request.body.ResourceDetails.type === 'boundary') { + request.body.ResourceDetails.campaignId = null; + } const persistMessage: any = { ResourceDetails: request.body.ResourceDetails }; - produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC); + await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC); } function getFacilityIds(data: any) { @@ -931,6 +1053,13 @@ async function getLocalizedMessagesHandler(request: any, tenantId: any, module = return localizationResponse; } +async function getLocalizedMessagesHandlerViaRequestInfo(RequestInfo: any, tenantId: any, module = config.localisation.localizationModule) { + const localisationcontroller = Localisation.getInstance(); + const locale = getLocaleFromRequestInfo(RequestInfo); + const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId); + return localizationResponse; +} + async function translateSchema(schema: any, localizationMap?: { [key: string]: string }) { @@ -983,25 +1112,78 @@ function getDifferentDistrictTabs(boundaryData: any, differentTabsBasedOnLevel: } -async function getConfigurableColumnHeadersFromSchemaForTargetSheet(request: any, hierarchy: any, boundaryData: any, differentTabsBasedOnLevel: any, localizationMap?: any) { +async function getConfigurableColumnHeadersFromSchemaForTargetSheet(request: any, hierarchy: any, boundaryData: any, differentTabsBasedOnLevel: any, campaignObject: any, localizationMap?: any) { const districtIndex = hierarchy.indexOf(differentTabsBasedOnLevel); - var headers = getLocalizedHeaders(hierarchy.slice(districtIndex), localizationMap); - - const headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request); + let headers: any; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + if (isSourceMicroplan) { + logger.info(`Source is Microplan.`); + headers = getLocalizedHeaders(hierarchy, localizationMap); + } + else { + headers = getLocalizedHeaders(hierarchy.slice(districtIndex), localizationMap); + } + const headerColumnsAfterHierarchy = await generateDynamicTargetHeaders(request, campaignObject, localizationMap); const localizedHeadersAfterHierarchy = getLocalizedHeaders(headerColumnsAfterHierarchy, localizationMap); - headers = [...headers, ...localizedHeadersAfterHierarchy] + headers = [...headers, getLocalizedName(config?.boundary?.boundaryCode, localizationMap), ...localizedHeadersAfterHierarchy] return getLocalizedHeaders(headers, localizationMap); } async function getMdmsDataBasedOnCampaignType(request: any, localizationMap?: any) { const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + let campaignType = campaignObject.projectType; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + campaignType = (isSourceMicroplan) ? `${config?.prefixForMicroplanCampaigns}-${campaignType}` : campaignType; const mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) return mdmsResponse; } +function appendProjectTypeToCapacity(schema: any, projectType: string): any { + const updatedSchema = JSON.parse(JSON.stringify(schema)); // Deep clone the schema + + const capacityKey = 'HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN'; + const newCapacityKey = `${capacityKey}_${projectType}`; + + // Update properties + if (updatedSchema.properties[capacityKey]) { + updatedSchema.properties[newCapacityKey] = { + ...updatedSchema.properties[capacityKey], + name: `${updatedSchema.properties[capacityKey].name}_${projectType}` + }; + delete updatedSchema.properties[capacityKey]; + } + + // Update required + updatedSchema.required = updatedSchema.required.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + // Update columns + updatedSchema.columns = updatedSchema.columns.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + // Update unique + updatedSchema.unique = updatedSchema.unique.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + // Update errorMessage + if (updatedSchema.errorMessage[capacityKey]) { + updatedSchema.errorMessage[newCapacityKey] = updatedSchema.errorMessage[capacityKey]; + delete updatedSchema.errorMessage[capacityKey]; + } + + // Update columnsNotToBeFreezed + updatedSchema.columnsNotToBeFreezed = updatedSchema.columnsNotToBeFreezed.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + return updatedSchema; +} export { @@ -1048,7 +1230,10 @@ export { changeFirstRowColumnColour, getConfigurableColumnHeadersFromSchemaForTargetSheet, createBoundaryDataMainSheet, - getMdmsDataBasedOnCampaignType + getMdmsDataBasedOnCampaignType, + shutdownGracefully, + appendProjectTypeToCapacity, + getLocalizedMessagesHandlerViaRequestInfo }; diff --git a/health-services/project-factory/src/server/utils/localisationUtils.ts b/health-services/project-factory/src/server/utils/localisationUtils.ts index 0b1bd4804be..3d5585947ef 100644 --- a/health-services/project-factory/src/server/utils/localisationUtils.ts +++ b/health-services/project-factory/src/server/utils/localisationUtils.ts @@ -6,7 +6,15 @@ export const getLocaleFromRequest = (request: any) => { const msgId = request?.body?.RequestInfo?.msgId; // Split msgId by '|' delimiter and get the second part (index 1) // If splitting fails or no second part is found, use default locale from config - return msgId.split("|")?.[1] || config?.localisation?.defaultLocale; + return msgId?.split("|")?.[1] || config?.localisation?.defaultLocale; +}; + +export const getLocaleFromRequestInfo = (RequestInfo: any) => { + // Extract msgId from request body + const msgId = RequestInfo?.msgId; + // Split msgId by '|' delimiter and get the second part (index 1) + // If splitting fails or no second part is found, use default locale from config + return msgId?.split("|")?.[1] || config?.localisation?.defaultLocale; }; // Function to generate localisation module name based on hierarchy type @@ -22,17 +30,17 @@ export const getLocalisationModuleName = (hierarchyType: any) => { * @returns The transformed locale string. */ export const getTransformedLocale = (label: string) => { - // Trim leading and trailing whitespace from the label - label = label?.trim(); - // If label is not empty, convert to uppercase and replace special characters with underscores - return label && label.toUpperCase().replace(/[.:-\s\/]/g, "_"); - }; + // Trim leading and trailing whitespace from the label + label = label?.trim(); + // If label is not empty, convert to uppercase and replace special characters with underscores + return label && label.toUpperCase().replace(/[.:-\s\/]/g, "_"); +}; - export const convertLocalisationResponseToMap=(messages:any=[])=>{ - const localizationMap: any = {}; - messages.forEach((message: any) => { - localizationMap[message.code] = message.message; - }); - return localizationMap; - } \ No newline at end of file +export const convertLocalisationResponseToMap = (messages: any = []) => { + const localizationMap: any = {}; + messages.forEach((message: any) => { + localizationMap[message.code] = message.message; + }); + return localizationMap; +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/processTrackUtils.ts b/health-services/project-factory/src/server/utils/processTrackUtils.ts index d822e28fded..6d80346825f 100644 --- a/health-services/project-factory/src/server/utils/processTrackUtils.ts +++ b/health-services/project-factory/src/server/utils/processTrackUtils.ts @@ -1,52 +1,224 @@ import config from './../config'; -import { produceModifiedMessages } from '../kafka/Listener'; +import { produceModifiedMessages } from "../kafka/Producer";; import { v4 as uuidv4 } from 'uuid'; import { executeQuery } from './db'; +import { processTrackForUi, processTrackStatuses, processTrackTypes } from '../config/constants'; +import { logger } from './logger'; + +async function getProcessDetails(id: string, type?: string): Promise { + let query: string; + const values: any[] = [id]; + + logger.info(`Fetching process details for campaignId: ${id}${type ? `, type: ${type}` : ''}`); + + if (type) { + query = ` + SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_PROCESS_TABLE_NAME} + WHERE campaignid = $1 AND type = $2 + ORDER BY lastmodifiedtime ASC; + `; + values.push(type); + } else { + query = ` + SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_PROCESS_TABLE_NAME} + WHERE campaignid = $1 + ORDER BY lastmodifiedtime ASC; + `; + } -async function getProcessDetails(id: any): Promise { - const query = `SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_PROCESS_TABLE_NAME} WHERE id = $1`; - const values = [id]; const queryResponse = await executeQuery(query, values); - return queryResponse.rows[0]; // Assuming only one row is expected + + if (queryResponse.rows.length === 0) { + logger.info('No process details found'); + return []; + } + const uiSet = new Set(processTrackForUi.map((item: any) => item)); + return queryResponse.rows.map((result: any) => ({ + id: result.id, + campaignId: result.campaignid, + type: result.type, + status: result.status, + showInUi: uiSet.has(result.type), + details: result.details, + additionalDetails: result.additionaldetails, + createdTime: parseInt(result.createdtime, 10), + lastModifiedTime: parseInt(result.lastmodifiedtime, 10), + })); } async function persistTrack( - campaignId: any, - type: any, - status: any, - details?: any, - additionalDetails?: any, - id?: any + campaignId: string, + type: string, + status: string, + details?: Record, + additionalDetails?: Record +): Promise { + if (!campaignId) { + logger.info('campaignId is missing, aborting persistTrack'); + return; + } + + logger.info(`Persisting track for campaignId: ${campaignId}, type: ${type}, status: ${status}`); + + if (type == processTrackTypes.error) { + await handleFailedStatus(campaignId, type, status, details, additionalDetails); + } else { + await handleNonFailedStatus(campaignId, type, status, details, additionalDetails); + } +} + +// Handles the case when the status is 'failed' +async function handleFailedStatus( + campaignId: string, + type: string, + status: string, + details?: Record, + additionalDetails?: Record +): Promise { + const processDetailsArray = await getProcessDetails(campaignId); + const inProgressProcessDetails = processDetailsArray.filter((processDetail: any) => processDetail.status === processTrackStatuses.inprogress); + const toBeCompletedProcessDetails = processDetailsArray.filter((processDetail: any) => processDetail.status === processTrackStatuses.toBeCompleted); + const failedStatusArray = processDetailsArray.filter((processDetail: any) => processDetail.status === processTrackStatuses.failed); + if (failedStatusArray.length > 0) { + logger.info('Process already failed, nothing to persist'); + await updateToBeCompletedProcess(toBeCompletedProcessDetails, status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); + return; + } + if (inProgressProcessDetails.length > 0) { + logger.info('Generic fail occured so changing the lastest inprogress status to failed'); + await updateAndProduceMessage(inProgressProcessDetails[inProgressProcessDetails.length - 1], status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); + } else { + logger.info('No inprogress process found, creating a new processDetail to failed'); + await createAndProduceNewProcessDetail(campaignId, type, status, details, additionalDetails, config?.kafka?.KAFKA_SAVE_PROCESS_TRACK_TOPIC); + } + await updateToBeCompletedProcess(toBeCompletedProcessDetails, status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); +} + +async function updateToBeCompletedProcess( + processDetailsArray: any[], + status: string, + details?: Record, + additionalDetails?: Record, + kafkaTopic?: string) { + details = details || {}, + details.error = "HCM_PROCESS_TRACK_PREVIOUS_PROCESS_FAILED" + if (processDetailsArray.length > 0) { + for (let i = 0; i < processDetailsArray.length; i++) { + await updateAndProduceMessage(processDetailsArray[i], status, details, additionalDetails, kafkaTopic); + } + } +} + +// Handles the case when the status is not 'failed' +async function handleNonFailedStatus( + campaignId: string, + type: string, + status: string, + details?: Record, + additionalDetails?: Record ): Promise { - let processDetails: any; + const processDetailsArray = await getProcessDetails(campaignId, type); - if (id) { - processDetails = await getProcessDetails(id); - details = { ...processDetails?.details, ...details }; - additionalDetails = { ...processDetails?.additionalDetails, ...additionalDetails }; + if (processDetailsArray.length === 0) { + logger.info('No process details found, nothing to persist'); + return; } - const processId = id || uuidv4(); - const createdTime = Date.now(); - const lastModifiedTime = Date.now(); + updateAndProduceMessage(processDetailsArray[0], status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); +} + +// Updates an existing process detail and produces the message +async function updateAndProduceMessage( + processDetails: any, + status: string, + details?: Record, + additionalDetails?: Record, + kafkaTopic?: string +) { + updateProcessDetails(processDetails, processDetails.type, status, details, additionalDetails); + const produceMessage: any = { processDetails }; + await produceModifiedMessages(produceMessage, kafkaTopic); +} - processDetails = { - id: processId, +// Creates a new process detail and produces the message +async function createAndProduceNewProcessDetail( + campaignId: string, + type: string, + status: string, + details?: Record, + additionalDetails?: Record, + kafkaTopic?: string +) { + const currentTime = Date.now(); + const processDetail: any = { + id: uuidv4(), campaignId, type, status, - details, - additionalDetails, - createdTime, - lastModifiedTime + createdTime: currentTime, + lastModifiedTime: currentTime, + details: details || {}, + additionalDetails: additionalDetails || {}, }; - const produceObject: any = { - processDetails - }; + updateProcessDetails(processDetail, type, status, details, additionalDetails); + const produceMessage: any = { processDetails: [processDetail] }; + await produceModifiedMessages(produceMessage, kafkaTopic); +} + + +function updateProcessDetails( + processDetails: any, + type: string, + status: string, + details?: any, + additionalDetails?: any +) { + processDetails.lastModifiedTime = Date.now(); + processDetails.details = { ...processDetails.details, ...details }; + processDetails.additionalDetails = { ...processDetails.additionalDetails, ...additionalDetails }; + processDetails.type = type; + processDetails.status = status; +} + +async function createProcessTracks(campaignId: string) { + logger.info(`Creating process tracks for campaignId: ${campaignId}`); + + const processDetailsArray: any[] = []; + + Object.keys(processTrackTypes).forEach(key => { + const type: any = (processTrackTypes as any)[key]; + const currentTime = Date.now(); + if (type != processTrackTypes.error) { + const processDetail: any = { + id: uuidv4(), + campaignId, + type, + status: processTrackStatuses.toBeCompleted, + createdTime: currentTime, + lastModifiedTime: currentTime, + details: {}, + additionalDetails: {} + }; + processDetailsArray.push(processDetail); + } + }); + + logger.info(`Created ${processDetailsArray.length} process tracks`); + const produceMessage: any = { processDetails: processDetailsArray } + await produceModifiedMessages(produceMessage, config?.kafka?.KAFKA_SAVE_PROCESS_TRACK_TOPIC); +} + +function getOrderedDetailsArray(toBeCompletedArray: any[]) { + const order = Object.values(processTrackTypes); + return toBeCompletedArray.sort((a, b) => order.indexOf(a.type) - order.indexOf(b.type)); +} - const topic = id ? config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC : config?.kafka?.KAFKA_SAVE_PROCESS_TRACK_TOPIC; - produceModifiedMessages(produceObject, topic); +export function modifyProcessDetails(processDetailsArray: any[]) { + const toBeCompletedArray = processDetailsArray.filter((item: any) => item.status === processTrackStatuses.toBeCompleted); + const orderedToBeCompletedArray = getOrderedDetailsArray(toBeCompletedArray); + const otherArray = processDetailsArray.filter((item: any) => item.status !== processTrackStatuses.toBeCompleted); + return otherArray.concat(orderedToBeCompletedArray); } -export { persistTrack }; \ No newline at end of file +export { persistTrack, getProcessDetails, createProcessTracks }; diff --git a/health-services/project-factory/src/server/utils/targetUtils.ts b/health-services/project-factory/src/server/utils/targetUtils.ts new file mode 100644 index 00000000000..74a91782dba --- /dev/null +++ b/health-services/project-factory/src/server/utils/targetUtils.ts @@ -0,0 +1,137 @@ +import config from '../config' +import { checkIfSourceIsMicroplan, getConfigurableColumnHeadersBasedOnCampaignType, getLocalizedName } from './campaignUtils'; +import _ from 'lodash'; +import { replicateRequest } from './genericUtils'; +import { callGenerate } from './generateUtils'; + + +async function generateDynamicTargetHeaders(request: any, campaignObject: any, localizationMap?: any) { + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + let headerColumnsAfterHierarchy: any; + if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0 && !isSourceMicroplan) { + const modifiedUniqueDeliveryConditions = modifyDeliveryConditions(campaignObject.deliveryRules); + headerColumnsAfterHierarchy = generateTargetColumnsBasedOnDeliveryConditions(modifiedUniqueDeliveryConditions, localizationMap); + + } + else { + headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request); + headerColumnsAfterHierarchy.shift(); + } + return headerColumnsAfterHierarchy; +} + + +function modifyDeliveryConditions(dataa: any[]): any { + let resultSet = new Set(); + dataa.forEach((delivery) => { + const conditions = delivery.conditions; + let newArray: any[] = []; + + conditions.forEach((item: any) => { + const existingIndex = newArray.findIndex( + (element) => element.attribute.code === item.attribute + ); + + if (existingIndex !== -1) { + const existingItem = newArray[existingIndex]; + // Combine conditions if necessary + if (existingItem.operator.code !== item.operator.code) { + newArray[existingIndex] = { + attribute: existingItem.attribute, + operator: { code: "IN_BETWEEN" }, + toValue: + existingItem.value && item.value ? Math.max(existingItem.value, item.value) : null, + fromValue: + existingItem.value && item.value ? Math.min(existingItem.value, item.value) : null + }; + } + } else { + // If attribute does not exist in newArray, add the item + newArray.push({ + attribute: { code: item.attribute }, + operator: { code: item.operator }, + value: item.value + }); + } + }); + newArray.map((element: any) => { + const stringifiedElement = JSON.stringify(element); // Convert object to string + resultSet.add(stringifiedElement); + }) + }); + return resultSet; +} + + +function generateTargetColumnsBasedOnDeliveryConditions(uniqueDeliveryConditions: any, localizationMap?: any) { + const targetColumnsBasedOnDeliveryConditions: string[] = []; + uniqueDeliveryConditions.forEach((str: any, index: number) => { + const uniqueDeliveryConditionsObject = JSON.parse(str); // Parse JSON string into object + const targetColumnString = createTargetString(uniqueDeliveryConditionsObject, localizationMap); + targetColumnsBasedOnDeliveryConditions.push(targetColumnString); + }); + if (targetColumnsBasedOnDeliveryConditions.length > 18) { + targetColumnsBasedOnDeliveryConditions.splice(18); + targetColumnsBasedOnDeliveryConditions.push(getLocalizedName("OTHER_TARGETS", localizationMap)); + } + return targetColumnsBasedOnDeliveryConditions; +} + +function createTargetString(uniqueDeliveryConditionsObject: any, localizationMap?: any) { + let targetString: any; + const prefix = getLocalizedName("HCM_ADMIN_CONSOLE_TARGET_SMC", localizationMap); + const attributeCode = getLocalizedName(uniqueDeliveryConditionsObject.attribute.code.toUpperCase(), localizationMap); + const operatorMessage = getLocalizedName(uniqueDeliveryConditionsObject.operator.code, localizationMap); + const localizedFROM = getLocalizedName("FROM", localizationMap); + const localizedTO = getLocalizedName("TO", localizationMap); + if (uniqueDeliveryConditionsObject.operator.code === 'IN_BETWEEN') { + targetString = `${prefix} ${attributeCode} ${localizedFROM} ${uniqueDeliveryConditionsObject.fromValue} ${localizedTO} ${uniqueDeliveryConditionsObject.toValue}`; + } else { + targetString = `${prefix} ${attributeCode} ${operatorMessage} ${uniqueDeliveryConditionsObject.value}`; + } + return targetString; +} + +async function updateTargetColumnsIfDeliveryConditionsDifferForSMC(request: any) { + const existingCampaignDetails = request?.body?.ExistingCampaignDetails; + if (existingCampaignDetails) { + if (isDynamicTargetTemplateForProjectType(request?.body?.CampaignDetails?.projectType) && config?.isCallGenerateWhenDeliveryConditionsDiffer && !_.isEqual(existingCampaignDetails?.deliveryRules, request?.body?.CampaignDetails?.deliveryRules)) { + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, + Filters: { + boundaries: request?.body?.CampaignDetails?.boundaries + } + }; + + const { query } = request; + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + forceUpdate: 'true', + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + campaignId: request?.body?.CampaignDetails?.id + }; + + const newParamsBoundary = { ...query, ...params, type: "boundary" }; + const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); + await callGenerate(newRequestBoundary, "boundary", true); + } + } +} + +function isDynamicTargetTemplateForProjectType(projectType: string) { + const projectTypesFromConfig = config?.enableDynamicTemplateFor; + const projectTypesArray = projectTypesFromConfig ? projectTypesFromConfig.split(',') : []; + return projectTypesArray.includes(projectType); +} + + + + + +export { + modifyDeliveryConditions, + generateTargetColumnsBasedOnDeliveryConditions, + generateDynamicTargetHeaders, + updateTargetColumnsIfDeliveryConditionsDifferForSMC, + isDynamicTargetTemplateForProjectType +}; diff --git a/health-services/project-factory/src/server/validators/campaignValidators.ts b/health-services/project-factory/src/server/validators/campaignValidators.ts index cddd2c9958a..8c50b9bcd46 100644 --- a/health-services/project-factory/src/server/validators/campaignValidators.ts +++ b/health-services/project-factory/src/server/validators/campaignValidators.ts @@ -2,7 +2,7 @@ import createAndSearch from "../config/createAndSearch"; import config from "../config"; import { getFormattedStringForDebug, logger } from "../utils/logger"; import { defaultheader, httpRequest } from "../utils/request"; -import { getHeadersOfBoundarySheet, getHierarchy, handleResouceDetailsError } from "../api/campaignApis"; +import { getCampaignSearchResponse, getHeadersOfBoundarySheet, getHierarchy, handleResouceDetailsError } from "../api/campaignApis"; import { campaignDetailsSchema } from "../config/models/campaignDetails"; import Ajv from "ajv"; import { getDifferentDistrictTabs, getLocalizedHeaders, getLocalizedMessagesHandler, getMdmsDataBasedOnCampaignType, replicateRequest, throwError } from "../utils/genericUtils"; @@ -20,7 +20,7 @@ import { searchProjectTypeCampaignService } from "../service/campaignManageServi import { campaignStatuses, resourceDataStatuses } from "../config/constants"; import { getBoundaryColumnName, getBoundaryTabName } from "../utils/boundaryUtils"; import addAjvErrors from "ajv-errors"; - +import { generateTargetColumnsBasedOnDeliveryConditions, isDynamicTargetTemplateForProjectType, modifyDeliveryConditions } from "../utils/targetUtils"; @@ -83,75 +83,75 @@ async function fetchBoundariesFromCampaignDetails(request: any) { return responseBoundaries; } -// Compares unique boundaries with response boundaries and throws error for missing codes. -function compareBoundariesWithUnique(uniqueBoundaries: any[], responseBoundaries: any[], request: any) { - // Extracts boundary codes from response boundaries - const responseBoundaryCodes = responseBoundaries.map(boundary => boundary.code.trim()); - - // Finds missing codes from unique boundaries - const missingCodes = uniqueBoundaries.filter(code => !responseBoundaryCodes.includes(code)); - - // Throws error if missing codes exist - if (missingCodes.length > 0) { - throwError( - "COMMON", - 400, - "VALIDATION_ERROR", - `Boundary codes ${missingCodes.join(', ')} do not exist in hierarchyType ${request?.body?.ResourceDetails?.hierarchyType}` - ); - } -} +// // Compares unique boundaries with response boundaries and throws error for missing codes. +// function compareBoundariesWithUnique(uniqueBoundaries: any[], responseBoundaries: any[], request: any) { +// // Extracts boundary codes from response boundaries +// const responseBoundaryCodes = responseBoundaries.map(boundary => boundary.code.trim()); + +// // Finds missing codes from unique boundaries +// const missingCodes = uniqueBoundaries.filter(code => !responseBoundaryCodes.includes(code)); + +// // Throws error if missing codes exist +// if (missingCodes.length > 0) { +// throwError( +// "COMMON", +// 400, +// "VALIDATION_ERROR", +// `Boundary codes ${missingCodes.join(', ')} do not exist in hierarchyType ${request?.body?.ResourceDetails?.hierarchyType}` +// ); +// } +// } // Validates unique boundaries against the response boundaries. -async function validateUniqueBoundaries(uniqueBoundaries: any[], request: any) { - // Fetches response boundaries in chunks - const responseBoundaries = await fetchBoundariesInChunks(request); +// async function validateUniqueBoundaries(uniqueBoundaries: any[], request: any) { +// // Fetches response boundaries in chunks +// const responseBoundaries = await fetchBoundariesInChunks(request); - // Compares unique boundaries with response boundaries - compareBoundariesWithUnique(uniqueBoundaries, responseBoundaries, request); -} +// // Compares unique boundaries with response boundaries +// compareBoundariesWithUnique(uniqueBoundaries, responseBoundaries, request); +// } -async function validateBoundaryData(data: any[], request: any, boundaryColumn: any, localizationMap: any) { - const boundarySet = new Set(); // Create a Set to store unique boundaries - logger.info("validating for the boundary data") - const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; - const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap) : null; - if (activeColumnName && uniqueIdentifierColumnName) { - data = data.filter((item: any) => item[activeColumnName] === "Active" || !item[uniqueIdentifierColumnName]); - data.forEach((item: any) => item[activeColumnName] = "Active"); - } - if (data.length == 0) { - if (request?.body?.ResourceDetails?.type == "facility") { - throwError("COMMON", 400, "VALIDATION_ERROR", "All facilities are set to Inactive for this campaign. Please set at least one facility to Active for this campaign or add a new facility for this campaign"); - } - else { - throwError("COMMON", 400, "VALIDATION_ERROR", "Data is empty for this campaign, add atleast one data row"); - } - } - data.forEach((element) => { - const boundaries = element[boundaryColumn]; - if (!boundaries) { - throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Code is required for element in rowNumber ${element['!row#number!']}`); - } +// async function validateBoundaryData(data: any[], request: any, boundaryColumn: any, localizationMap: any) { +// const boundarySet = new Set(); // Create a Set to store unique boundaries +// logger.info("validating for the boundary data") +// const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; +// const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap) : null; +// if (activeColumnName && uniqueIdentifierColumnName) { +// data = data.filter((item: any) => item[activeColumnName] === "Active" || !item[uniqueIdentifierColumnName]); +// data.forEach((item: any) => item[activeColumnName] = "Active"); +// } +// if (data.length == 0) { +// if (request?.body?.ResourceDetails?.type == "facility") { +// throwError("COMMON", 400, "VALIDATION_ERROR", "All facilities are set to Inactive for this campaign. Please set at least one facility to Active for this campaign or add a new facility for this campaign"); +// } +// else { +// throwError("COMMON", 400, "VALIDATION_ERROR", "Data is empty for this campaign, add atleast one data row"); +// } +// } +// data.forEach((element) => { +// const boundaries = element[boundaryColumn]; +// if (!boundaries) { +// throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Code is required for element in rowNumber ${element['!row#number!']}`); +// } - const boundaryList = boundaries.split(",").map((boundary: any) => boundary.trim()); - if (boundaryList.length === 0) { - throwError("COMMON", 400, "VALIDATION_ERROR", `At least 1 boundary is required for element in rowNumber ${element['!row#number!']}`); - } +// const boundaryList = boundaries.split(",").map((boundary: any) => boundary.trim()); +// if (boundaryList.length === 0) { +// throwError("COMMON", 400, "VALIDATION_ERROR", `At least 1 boundary is required for element in rowNumber ${element['!row#number!']}`); +// } - for (const boundary of boundaryList) { - if (!boundary) { - throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary format is invalid in rowNumber ${element['!row#number!']}. Put it with one comma between boundary codes`); - } - boundarySet.add(boundary); // Add boundary to the set - } - }); - const uniqueBoundaries = Array.from(boundarySet); - await validateUniqueBoundaries(uniqueBoundaries, request); -} +// for (const boundary of boundaryList) { +// if (!boundary) { +// throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary format is invalid in rowNumber ${element['!row#number!']}. Put it with one comma between boundary codes`); +// } +// boundarySet.add(boundary); // Add boundary to the set +// } +// }); +// const uniqueBoundaries = Array.from(boundarySet); +// await validateUniqueBoundaries(uniqueBoundaries, request); +// } // async function validateTargetBoundaryData(data: any[], request: any, boundaryColumn: any, errors: any[], localizationMap?: any) { // // const responseBoundaries = await fetchBoundariesInChunks(request); @@ -217,10 +217,21 @@ async function validateBoundaryData(data: any[], request: any, boundaryColumn: a async function validateTargets(request: any, data: any[], errors: any[], localizationMap?: any) { - const mdmsResponse = await getMdmsDataBasedOnCampaignType(request); - const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; - const requiredColumns = mdmsResponse?.required; - const columnsToValidate = columnsNotToBeFreezed.filter((element: any) => requiredColumns.includes(element)); + let columnsToValidate: any; + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0) { + + const modifiedUniqueDeliveryConditions = modifyDeliveryConditions(campaignObject.deliveryRules); + columnsToValidate = generateTargetColumnsBasedOnDeliveryConditions(modifiedUniqueDeliveryConditions, localizationMap); + + } + else { + const mdmsResponse = await getMdmsDataBasedOnCampaignType(request); + const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + const requiredColumns = mdmsResponse?.required; + columnsToValidate = columnsNotToBeFreezed.filter((element: any) => requiredColumns.includes(element)); + } const localizedTargetColumnNames = getLocalizedHeaders(columnsToValidate, localizationMap); for (const key in data) { if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { @@ -411,16 +422,12 @@ async function validateViaSchema(data: any, schema: any, request: any, localizat async function validateSheetData(data: any, request: any, schema: any, boundaryValidation: any, localizationMap?: { [key: string]: string }) { await validateViaSchema(data, schema, request, localizationMap); - if (boundaryValidation) { - const localisedBoundaryCode = getLocalizedName(boundaryValidation?.column, localizationMap) - await validateBoundaryData(data, request, localisedBoundaryCode, localizationMap); - } } -async function validateTargetSheetData(data: any, request: any, boundaryValidation: any, localizationMap?: any) { +async function validateTargetSheetData(data: any, request: any, boundaryValidation: any, differentTabsBasedOnLevel: any, localizationMap?: any) { try { const errors: any[] = []; - await validateHeadersOfTargetSheet(request, localizationMap); + await validateHeadersOfTargetSheet(request, differentTabsBasedOnLevel, localizationMap); if (boundaryValidation) { // const localizedBoundaryValidationColumn = getLocalizedName(boundaryValidation?.column, localizationMap) // await validateTargetBoundaryData(data, request, localizedBoundaryValidationColumn, errors, localizationMap); @@ -440,11 +447,11 @@ async function validateTargetSheetData(data: any, request: any, boundaryValidati } -async function validateHeadersOfTargetSheet(request: any, localizationMap?: any) { +async function validateHeadersOfTargetSheet(request: any, differentTabsBasedOnLevel: any, localizationMap?: any) { const fileUrl = await validateFile(request); const targetWorkbook: any = await getTargetWorkbook(fileUrl); const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); - const finalValidHeadersForTargetSheetAsPerCampaignType = await getFinalValidHeadersForTargetSheetAsPerCampaignType(request, hierarchy, localizationMap); + const finalValidHeadersForTargetSheetAsPerCampaignType = await getFinalValidHeadersForTargetSheetAsPerCampaignType(request, hierarchy, differentTabsBasedOnLevel, localizationMap); logger.info("finalValidHeadersForTargetSheetAsPerCampaignType :" + JSON.stringify(finalValidHeadersForTargetSheetAsPerCampaignType)); logger.info("validating headers of target sheet started") validateHeadersOfTabsWithTargetInTargetSheet(targetWorkbook, finalValidHeadersForTargetSheetAsPerCampaignType); @@ -712,7 +719,7 @@ async function validateBoundariesForTabs(CampaignDetails: any, resource: any, re const resourceBoundaryCodesArray: any[] = []; var activeColumnName: any = null; if (createAndSearch?.[resource.type]?.activeColumn && createAndSearch?.[resource.type]?.activeColumnName) { - activeColumnName = getLocalizedName(createAndSearch?.[resource.type]?.activeColumn, localizationMap); + activeColumnName = getLocalizedName(createAndSearch?.[resource.type]?.activeColumnName, localizationMap); } datas.forEach((data: any) => { const codes = data?.[boundaryColumn]?.split(',').map((code: string) => code.trim()) || []; @@ -730,7 +737,7 @@ async function validateBoundariesForTabs(CampaignDetails: any, resource: any, re var missingBoundaries = rowData.boundaryCodes.filter((code: any) => !boundaryCodesArray.includes(code)); if (missingBoundaries.length > 0) { const errorString = `The following boundary codes are not present in selected boundaries : ${missingBoundaries.join(', ')}` - errors.push({ status: "BOUNDARYMISSING", rowNumber: rowData.rowNumber, errorDetails: errorString }) + errors.push({ status: "BOUNDARYERROR", rowNumber: rowData.rowNumber, errorDetails: errorString }) } } if (errors?.length > 0) { @@ -1159,9 +1166,9 @@ async function validateDownloadRequest(request: any) { await validateHierarchyType(request, hierarchyType, tenantId); } -async function immediateValidationForTargetSheet(dataFromSheet: any, localizationMap: any) { +async function immediateValidationForTargetSheet(request: any, dataFromSheet: any, differentTabsBasedOnLevel: any, localizationMap: any) { logger.info("validating all district tabs present started") - validateAllDistrictTabsPresentOrNot(dataFromSheet, localizationMap); + validateAllDistrictTabsPresentOrNot(request, dataFromSheet, differentTabsBasedOnLevel, localizationMap); logger.info("validation of all district tabs present completed") for (const key in dataFromSheet) { if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { @@ -1170,7 +1177,7 @@ async function immediateValidationForTargetSheet(dataFromSheet: any, localizatio if (dataArray.length === 0) { throwError("COMMON", 400, "VALIDATION_ERROR", `The Target Sheet ${key} you have uploaded is empty`) } - const root = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); + const root = getLocalizedName(differentTabsBasedOnLevel, localizationMap); for (const boundaryRow of dataArray) { for (const columns in boundaryRow) { if (columns.startsWith('__EMPTY')) { @@ -1187,16 +1194,15 @@ async function immediateValidationForTargetSheet(dataFromSheet: any, localizatio } -function validateAllDistrictTabsPresentOrNot(dataFromSheet: any, localizationMap?: any) { +function validateAllDistrictTabsPresentOrNot(request: any, dataFromSheet: any, differentTabsBasedOnLevel: any, localizationMap?: any) { let tabsIndex = 2; logger.info("target sheet getting validated for different districts"); - const differentTabsBasedOnLevel = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); const tabsOfDistrict = getDifferentDistrictTabs(dataFromSheet[getLocalizedName(config?.boundary?.boundaryTab, localizationMap)], differentTabsBasedOnLevel); logger.info("found " + tabsOfDistrict?.length + " districts"); logger.debug("actual districts in boundary data sheet : " + getFormattedStringForDebug(tabsOfDistrict)); const tabsFromTargetSheet = Object.keys(dataFromSheet); logger.info("districts present in user filled sheet : " + (tabsFromTargetSheet?.length - tabsIndex)); - logger.debug("districts present in user filled sheet : " + getFormattedStringForDebug(tabsFromTargetSheet)); + logger.debug("districts present in user filled sheet (exclude first two tabs): " + getFormattedStringForDebug(tabsFromTargetSheet)); if (tabsFromTargetSheet.length - tabsIndex !== tabsOfDistrict.length) { throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tabs uplaoded by user is either less or more than the ${differentTabsBasedOnLevel} in the boundary system `) @@ -1207,11 +1213,16 @@ function validateAllDistrictTabsPresentOrNot(dataFromSheet: any, localizationMap throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tab ${tab} not present in the Target Sheet Uploaded`); } } - } } +function validateSearchProcessTracksRequest(request: any) { + if (!request?.query?.campaignId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignId is required in params"); + } +} + export { fetchBoundariesInChunks, @@ -1227,5 +1238,6 @@ export { validateDownloadRequest, validateTargetSheetData, immediateValidationForTargetSheet, - validateBoundaryOfResouces + validateBoundaryOfResouces, + validateSearchProcessTracksRequest } diff --git a/health-services/project-factory/src/server/validators/genericValidator.ts b/health-services/project-factory/src/server/validators/genericValidator.ts index 426f1de67e7..245579d6134 100644 --- a/health-services/project-factory/src/server/validators/genericValidator.ts +++ b/health-services/project-factory/src/server/validators/genericValidator.ts @@ -7,6 +7,9 @@ import { httpRequest } from "../utils/request"; import { getBoundaryRelationshipData, throwError } from "../utils/genericUtils"; import { validateFilters } from "./campaignValidators"; import { generateRequestSchema } from "../config/models/generateRequestSchema"; +import { persistTrack } from "../utils/processTrackUtils"; +import { processTrackTypes, processTrackStatuses, campaignStatuses } from "../config/constants"; +import { validateMappingId } from "../utils/campaignMappingUtils"; // Function to validate data against a JSON schema function validateDataWithSchema(data: any, schema: any): { isValid: boolean; error: any | null | undefined } { @@ -30,6 +33,11 @@ function validateCampaignBodyViaSchema(schema: any, objectData: any) { const dataPath = error.dataPath.replace(/\//g, '.').replace(/^\./, ''); formattedErrorMessage = `${dataPath} ${error.message}`; } + else if (error?.instancePath) { + // Replace slash with dot and remove leading dot if present + const dataPath = error.instancePath.replace(/\//g, '.').replace(/^\./, ''); + formattedErrorMessage = `${dataPath} ${error.message}`; + } else { formattedErrorMessage = `${error.message}` } @@ -61,6 +69,11 @@ function validateBodyViaSchema(schema: any, objectData: any) { const dataPath = error.dataPath.replace(/\//g, '.').replace(/^\./, ''); formattedErrorMessage = `${dataPath} ${error.message}`; } + else if (error?.instancePath) { + // Replace slash with dot and remove leading dot if present + const dataPath = error.instancePath.replace(/\//g, '.').replace(/^\./, ''); + formattedErrorMessage = `${dataPath} ${error.message}`; + } else { formattedErrorMessage = `${error.message}` } @@ -115,15 +128,40 @@ async function validateCampaign(requestBody: any) { // Function to validate the entire campaign request async function validateCampaignRequest(requestBody: any) { - if (requestBody?.Campaign) { - if (!requestBody?.Campaign?.tenantId) { - throwError("COMMON", 400, "VALIDATION_ERROR", "Enter TenantId"); + await persistTrack(requestBody?.Campaign?.id, processTrackTypes.validateMappingResource, processTrackStatuses.inprogress); + try { + if (requestBody?.Campaign) { + if (!requestBody?.Campaign?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter TenantId"); + } + await validateCampaign(requestBody); + const id = requestBody?.Campaign?.id; + const campaignDetails = await validateMappingId(requestBody, id); + if (campaignDetails?.status == campaignStatuses.inprogress) { + logger.error("Campaign Already In Progress and Mapped"); + throwError("CAMPAIGN", 400, "CAMPAIGN_ALREADY_MAPPED"); + } } - await validateCampaign(requestBody); - } - else { - throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign is required"); + else { + throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign object is missing"); + } + if (requestBody?.CampaignDetails) { + if (!requestBody?.CampaignDetails?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter TenantId"); + } + if (!requestBody?.CampaignDetails?.id) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter id in CampaignDetails"); + } + } + else { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails is missing"); + } + } catch (error: any) { + console.log(error) + await persistTrack(requestBody?.Campaign?.id, processTrackTypes.validateMappingResource, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) } + await persistTrack(requestBody?.Campaign?.id, processTrackTypes.validateMappingResource, processTrackStatuses.completed); } // Function to validate and update project response and its ID @@ -220,4 +258,4 @@ export { validateGenerateRequest, validateHierarchyType, validateCampaignBodyViaSchema -}; \ No newline at end of file +}; diff --git a/health-services/project-factory/yarn.lock b/health-services/project-factory/yarn.lock index 0584dc93095..4e9c73bf0f7 100644 --- a/health-services/project-factory/yarn.lock +++ b/health-services/project-factory/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - "@ampproject/remapping@^2.2.0": version "2.3.0" resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz" @@ -15,14 +10,7 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.0.0": - version "7.12.11" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2": version "7.24.2" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== @@ -30,179 +18,148 @@ "@babel/highlight" "^7.24.2" picocolors "^1.0.0" -"@babel/code-frame@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" - integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== - dependencies: - "@babel/highlight" "^7.24.7" - picocolors "^1.0.0" +"@babel/compat-data@^7.23.5": + version "7.24.4" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz" + integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== -"@babel/compat-data@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.7.tgz#d23bbea508c3883ba8251fb4164982c36ea577ed" - integrity sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw== - -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.7.tgz#b676450141e0b52a3d43bc91da86aa608f950ac4" - integrity sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g== +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.8.0": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz" + integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.7" - "@babel/helper-compilation-targets" "^7.24.7" - "@babel/helper-module-transforms" "^7.24.7" - "@babel/helpers" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/template" "^7.24.7" - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.5" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-module-transforms" "^7.24.5" + "@babel/helpers" "^7.24.5" + "@babel/parser" "^7.24.5" + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.5" + "@babel/types" "^7.24.5" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.7", "@babel/generator@^7.7.2": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" - integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== +"@babel/generator@^7.24.5", "@babel/generator@^7.7.2": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz" + integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== dependencies: - "@babel/types" "^7.24.7" + "@babel/types" "^7.24.5" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz#4eb6c4a80d6ffeac25ab8cd9a21b5dfa48d503a9" - integrity sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg== +"@babel/helper-compilation-targets@^7.23.6": + version "7.23.6" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== dependencies: - "@babel/compat-data" "^7.24.7" - "@babel/helper-validator-option" "^7.24.7" + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" browserslist "^4.22.2" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-environment-visitor@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" - integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== - dependencies: - "@babel/types" "^7.24.7" +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== -"@babel/helper-function-name@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" - integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== dependencies: - "@babel/template" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" -"@babel/helper-hoist-variables@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" - integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ== +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== dependencies: - "@babel/types" "^7.24.7" + "@babel/types" "^7.22.5" -"@babel/helper-module-imports@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" - integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== +"@babel/helper-module-imports@^7.24.3": + version "7.24.3" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/types" "^7.24.0" -"@babel/helper-module-transforms@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz#31b6c9a2930679498db65b685b1698bfd6c7daf8" - integrity sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ== +"@babel/helper-module-transforms@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz" + integrity sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A== dependencies: - "@babel/helper-environment-visitor" "^7.24.7" - "@babel/helper-module-imports" "^7.24.7" - "@babel/helper-simple-access" "^7.24.7" - "@babel/helper-split-export-declaration" "^7.24.7" - "@babel/helper-validator-identifier" "^7.24.7" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.24.3" + "@babel/helper-simple-access" "^7.24.5" + "@babel/helper-split-export-declaration" "^7.24.5" + "@babel/helper-validator-identifier" "^7.24.5" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": - version "7.24.0" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz" - integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz" + integrity sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ== -"@babel/helper-simple-access@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" - integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== +"@babel/helper-simple-access@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz" + integrity sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ== dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/types" "^7.24.5" -"@babel/helper-split-export-declaration@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" - integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== +"@babel/helper-split-export-declaration@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz" + integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q== dependencies: - "@babel/types" "^7.24.7" + "@babel/types" "^7.24.5" -"@babel/helper-string-parser@^7.23.4": +"@babel/helper-string-parser@^7.24.1": version "7.24.1" resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz" integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== -"@babel/helper-string-parser@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" - integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-identifier@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" - integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== +"@babel/helper-validator-identifier@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz" + integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== -"@babel/helper-validator-option@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz#24c3bb77c7a425d1742eec8fb433b5a1b38e62f6" - integrity sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw== +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== -"@babel/helpers@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.7.tgz#aa2ccda29f62185acb5d42fb4a3a1b1082107416" - integrity sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg== +"@babel/helpers@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz" + integrity sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q== dependencies: - "@babel/template" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/highlight@^7.10.4", "@babel/highlight@^7.24.2": - version "7.24.2" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz" - integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.5" + "@babel/types" "^7.24.5" -"@babel/highlight@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" - integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== +"@babel/highlight@^7.24.2": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz" + integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw== dependencies: - "@babel/helper-validator-identifier" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.5" chalk "^2.4.2" js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" - integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz" + integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -302,16 +259,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.0" -"@babel/template@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" - integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/template@^7.3.3": +"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": version "7.24.0" resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz" integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== @@ -320,38 +268,29 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" -"@babel/traverse@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5" - integrity sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.7" - "@babel/helper-environment-visitor" "^7.24.7" - "@babel/helper-function-name" "^7.24.7" - "@babel/helper-hoist-variables" "^7.24.7" - "@babel/helper-split-export-declaration" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/types" "^7.24.7" +"@babel/traverse@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz" + integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== + dependencies: + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.24.5" + "@babel/parser" "^7.24.5" + "@babel/types" "^7.24.5" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.0", "@babel/types@^7.3.3": - version "7.24.0" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz" - integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz" + integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@babel/types@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2" - integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q== - dependencies: - "@babel/helper-string-parser" "^7.24.7" - "@babel/helper-validator-identifier" "^7.24.7" + "@babel/helper-string-parser" "^7.24.1" + "@babel/helper-validator-identifier" "^7.24.5" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -359,7 +298,7 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@colors/colors@1.6.0", "@colors/colors@^1.6.0": +"@colors/colors@^1.6.0", "@colors/colors@1.6.0": version "1.6.0" resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz" integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== @@ -423,7 +362,7 @@ "@ioredis/commands@^1.1.1": version "1.2.0" - resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" + resolved "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz" integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== "@isaacs/cliui@^8.0.2": @@ -670,14 +609,6 @@ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" @@ -686,6 +617,14 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@npmcli/agent@^2.0.0": version "2.2.2" resolved "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz" @@ -698,9 +637,9 @@ socks-proxy-agent "^8.0.3" "@npmcli/fs@^3.1.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz" - integrity sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w== + version "3.1.1" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz" + integrity sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg== dependencies: semver "^7.3.5" @@ -804,9 +743,9 @@ "@types/node" "*" "@types/express-serve-static-core@^4.17.33": - version "4.17.43" - resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz" - integrity sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg== + version "4.19.0" + resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz" + integrity sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ== dependencies: "@types/node" "*" "@types/qs" "*" @@ -897,6 +836,11 @@ expect "^29.0.0" pretty-format "^29.0.0" +"@types/lodash@^4.17.5": + version "4.17.5" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz" + integrity sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw== + "@types/mime@^1": version "1.3.5" resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz" @@ -931,9 +875,9 @@ pg-types "^4.0.1" "@types/qs@*": - version "6.9.14" - resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz" - integrity sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA== + version "6.9.15" + resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz" + integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg== "@types/range-parser@*": version "1.2.7" @@ -1024,7 +968,7 @@ acorn-walk@^8.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz" integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== -acorn@^7.4.0: +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^7.4.0: version "7.4.1" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== @@ -1059,7 +1003,17 @@ ajv-errors@^3.0.0: resolved "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz" integrity sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ== -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.10.0: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1118,7 +1072,14 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -1230,7 +1191,12 @@ async@^2.6.2: dependencies: lodash "^4.17.14" -async@^3.2.3, async@^3.2.4: +async@^3.2.3: + version "3.2.5" + resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + +async@^3.2.4: version "3.2.5" resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== @@ -1386,7 +1352,7 @@ bluebird@~3.4.1: resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz" integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA== -body-parser@1.20.2, body-parser@^1.20.2: +body-parser@^1.20.2, body-parser@1.20.2: version "1.20.2" resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz" integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== @@ -1426,7 +1392,7 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.22.2: +browserslist@^4.22.2, "browserslist@>= 4.21.0": version "4.23.0" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== @@ -1517,9 +1483,9 @@ bytes@3.1.2: integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== cacache@^18.0.0: - version "18.0.2" - resolved "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz" - integrity sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw== + version "18.0.3" + resolved "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz" + integrity sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg== dependencies: "@npmcli/fs" "^3.1.0" fs-minipass "^3.0.0" @@ -1561,9 +1527,9 @@ camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001587: - version "1.0.30001605" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz" - integrity sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ== + version "1.0.30001620" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz" + integrity sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew== cfb@^1.1.3, cfb@~1.2.1: version "1.2.2" @@ -1633,9 +1599,9 @@ ci-info@^3.2.0: integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: - version "1.2.3" - resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz" - integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + version "1.3.1" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz" + integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== clean-stack@^2.0.0: version "2.2.0" @@ -1658,7 +1624,7 @@ clone@2.x: cluster-key-slot@^1.1.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz" integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== co@^4.6.0: @@ -1681,7 +1647,14 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== -color-convert@^1.9.0, color-convert@^1.9.3: +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^1.9.3: version "1.9.3" resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -1695,16 +1668,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + color-string@^1.6.0: version "1.9.1" resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" @@ -1853,14 +1826,21 @@ dayjs@^1.8.34: resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz" integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== -debug@2.6.9, debug@^2.1.3: +debug@^2.1.3, debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.3.1, debug@^4.3.4: +debug@^4.0.1: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + +debug@^4.1.0: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1874,6 +1854,27 @@ debug@^4.1.1: dependencies: ms "2.1.2" +debug@^4.3.1: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.3.4: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + +debug@4: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz" @@ -1882,9 +1883,9 @@ decompress-response@^3.3.0: mimic-response "^1.0.0" dedent@^1.0.0: - version "1.5.1" - resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz" - integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + version "1.5.3" + resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deep-extend@^0.6.0: version "0.6.0" @@ -1927,10 +1928,10 @@ denque@^1.3.0: denque@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" + resolved "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz" integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== -depd@2.0.0, depd@~2.0.0: +depd@~2.0.0, depd@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -1992,9 +1993,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.668: - version "1.4.806" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz#2cb046631cbabceb26fc72be68d273fa183e36bc" - integrity sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg== + version "1.4.772" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.772.tgz" + integrity sha512-jFfEbxR/abTTJA3ci+2ok1NTuOBBtB4jH+UT6PUmRN+DY3WSD4FFRsgoVQ+QNIJ0T7wrXwzsWCI2WKC46b++2A== emittery@^0.13.1: version "0.13.1" @@ -2060,7 +2061,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -error@7.0.2, error@^7.0.0: +error@^7.0.0, error@7.0.2: version "7.0.2" resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz" integrity sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw== @@ -2080,7 +2081,7 @@ es-errors@^1.3.0: resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -escalade@^3.1.1: +escalade@^3.1.1, escalade@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== @@ -2127,7 +2128,12 @@ eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== @@ -2189,16 +2195,21 @@ espree@^7.3.0, espree@^7.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -esprima@1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz" - integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A== +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esprima@1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz" + integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A== + esquery@^1.2.0: version "1.5.0" resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" @@ -2218,7 +2229,12 @@ estraverse@^4.1.1, estraverse@^4.2.0: resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0, estraverse@^5.2.0: +estraverse@^5.1.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estraverse@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -2431,9 +2447,9 @@ follow-redirects@^1.0.0, follow-redirects@^1.15.6: integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== foreground-child@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz" - integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + version "3.2.0" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz" + integrity sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" @@ -2486,11 +2502,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - fstream@^1.0.12: version "1.0.12" resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz" @@ -2569,17 +2580,41 @@ glob-parent@^5.0.0, glob-parent@~5.1.2: is-glob "^4.0.1" glob@^10.2.2, glob@^10.3.10: - version "10.3.12" - resolved "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz" - integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== + version "10.4.1" + resolved "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz" + integrity sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw== dependencies: foreground-child "^3.1.0" - jackspeak "^2.3.6" - minimatch "^9.0.1" - minipass "^7.0.4" - path-scurry "^1.10.2" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + path-scurry "^1.11.1" -glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.2.3: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -2737,13 +2772,6 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - iconv-lite@^0.6.2: version "0.6.3" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" @@ -2751,6 +2779,13 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + ieee754@^1.1.13: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" @@ -2800,7 +2835,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3: +inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3, inherits@2, inherits@2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2812,7 +2847,7 @@ ini@~1.3.0: ioredis@^5.4.1: version "5.4.1" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.4.1.tgz#1c56b70b759f01465913887375ed809134296f40" + resolved "https://registry.npmjs.org/ioredis/-/ioredis-5.4.1.tgz" integrity sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA== dependencies: "@ioredis/commands" "^1.1.1" @@ -2979,10 +3014,10 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jackspeak@^2.3.6: - version "2.3.6" - resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz" - integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== +jackspeak@^3.1.2: + version "3.4.0" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz" + integrity sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -3203,7 +3238,7 @@ jest-resolve-dependencies@^29.7.0: jest-regex-util "^29.6.3" jest-snapshot "^29.7.0" -jest-resolve@^29.7.0: +jest-resolve@*, jest-resolve@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== @@ -3546,7 +3581,7 @@ lodash.groupby@^4.6.0: lodash.isarguments@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz" integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== lodash.isboolean@^3.0.3: @@ -3594,7 +3629,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@4.17.21, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4: +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3611,20 +3646,20 @@ logform@^2.3.2, logform@^2.4.0: safe-stable-stringify "^2.3.1" triple-beam "^1.3.0" -long@1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/long/-/long-1.1.2.tgz" - integrity sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q== - long@^2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/long/-/long-2.4.0.tgz" integrity sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ== +long@1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/long/-/long-1.1.2.tgz" + integrity sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q== + lru-cache@^10.0.1, lru-cache@^10.2.0: - version "10.2.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz" - integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + version "10.2.2" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz" + integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== lru-cache@^5.1.1: version "5.1.1" @@ -3633,13 +3668,6 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - make-dir@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" @@ -3653,9 +3681,9 @@ make-error@^1.1.1: integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== make-fetch-happen@^13.0.0: - version "13.0.0" - resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz" - integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A== + version "13.0.1" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz" + integrity sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA== dependencies: "@npmcli/agent" "^2.0.0" cacache "^18.0.0" @@ -3666,6 +3694,7 @@ make-fetch-happen@^13.0.0: minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" negotiator "^0.6.3" + proc-log "^4.2.0" promise-retry "^2.0.1" ssri "^10.0.0" @@ -3704,7 +3733,7 @@ micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" -mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": +"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -3745,7 +3774,7 @@ minimatch@^5.1.0: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.1: +minimatch@^9.0.4: version "9.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz" integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== @@ -3765,9 +3794,9 @@ minipass-collect@^2.0.1: minipass "^7.0.3" minipass-fetch@^3.0.0: - version "3.0.4" - resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz" - integrity sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg== + version "3.0.5" + resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz" + integrity sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg== dependencies: minipass "^7.0.3" minipass-sized "^1.0.3" @@ -3803,16 +3832,16 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + minipass@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4: - version "7.0.4" - resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz" - integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== - minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" @@ -3821,14 +3850,19 @@ minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" -"mkdirp@>=0.5 0", mkdirp@^0.5.1: +mkdirp@^0.5.1, "mkdirp@>=0.5 0": version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: minimist "^1.2.6" -mkdirp@^1.0.3, mkdirp@^1.0.4: +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -3844,6 +3878,11 @@ morgan@1.10.0: on-finished "~2.3.0" on-headers "~1.0.2" +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" @@ -3854,7 +3893,7 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3874,7 +3913,7 @@ natural-compare@^1.4.0: resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@0.6.3, negotiator@^0.6.3: +negotiator@^0.6.3, negotiator@0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== @@ -3930,9 +3969,9 @@ noop-logger@^0.1.1: integrity sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ== nopt@^7.0.0: - version "7.2.0" - resolved "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz" - integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== + version "7.2.1" + resolved "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz" + integrity sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w== dependencies: abbrev "^2.0.0" @@ -3978,13 +4017,6 @@ obuf@~1.1.2: resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - on-finished@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" @@ -3992,6 +4024,13 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + on-headers@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" @@ -4041,16 +4080,16 @@ optionator@^0.8.1: word-wrap "~1.2.3" optionator@^0.9.1: - version "0.9.3" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + version "0.9.4" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" + word-wrap "^1.2.5" os-homedir@^1.0.1: version "1.0.2" @@ -4137,10 +4176,10 @@ path-parse@^1.0.7: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.2: - version "1.10.2" - resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz" - integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -4204,7 +4243,7 @@ pg-types@^4.0.1: postgres-interval "^3.0.0" postgres-range "^1.1.1" -pg@8.12.0: +pg@>=8.0, pg@8.12.0: version "8.12.0" resolved "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz" integrity sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ== @@ -4224,10 +4263,10 @@ pgpass@1.x: dependencies: split2 "^4.1.0" -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -4341,6 +4380,11 @@ proc-log@^3.0.0: resolved "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz" integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== +proc-log@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz" + integrity sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" @@ -4456,9 +4500,9 @@ rc@^1.2.7: strip-json-comments "~2.0.1" react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + version "18.3.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: version "2.3.8" @@ -4498,12 +4542,12 @@ readdirp@~3.6.0: redis-errors@^1.0.0, redis-errors@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + resolved "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz" integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== redis-parser@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + resolved "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz" integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== dependencies: redis-errors "^1.0.0" @@ -4569,7 +4613,7 @@ retry@^0.12.0: resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== -rimraf@2, rimraf@^2.6.1: +rimraf@^2.6.1: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -4583,7 +4627,14 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +rimraf@2: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -4620,17 +4671,35 @@ semver@^5.4.1: resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.3.0, semver@^6.3.1: +semver@^6.3.0: version "6.3.1" resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.2.1, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: - version "7.6.0" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.2.1: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.3.5: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.5.3: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.5.4: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== send@0.18.0: version "0.18.0" @@ -4784,14 +4853,14 @@ socks-proxy-agent@^8.0.3: socks "^2.7.1" socks@^2.7.1: - version "2.8.1" - resolved "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz" - integrity sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ== + version "2.8.3" + resolved "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz" + integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== dependencies: ip-address "^9.0.5" smart-buffer "^4.2.0" -source-map-support@0.5.13, source-map-support@^0.5.12: +source-map-support@^0.5.12, source-map-support@0.5.13: version "0.5.13" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== @@ -4827,9 +4896,9 @@ ssf@~0.11.2: frac "~1.1.2" ssri@^10.0.0: - version "10.0.5" - resolved "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz" - integrity sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A== + version "10.0.6" + resolved "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz" + integrity sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ== dependencies: minipass "^7.0.3" @@ -4847,7 +4916,7 @@ stack-utils@^2.0.3: standard-as-callback@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + resolved "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz" integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== static-eval@2.0.2: @@ -4862,6 +4931,13 @@ statuses@2.0.1: resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +string_decoder@^1.1.1, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + string-length@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" @@ -4893,7 +4969,7 @@ string-width@^1.0.1, "string-width@^1.0.2 || 2 || 3 || 4": is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4902,7 +4978,16 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.1, string-width@^5.1.2: +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1: version "5.1.2" resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== @@ -4911,12 +4996,14 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string_decoder@^1.1.1, string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== +string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: - safe-buffer "~5.1.0" + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" @@ -4966,7 +5053,12 @@ strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -5162,7 +5254,7 @@ ts-node-dev@2.0.0: ts-node "^10.4.0" tsconfig "^7.0.0" -ts-node@^10.4.0: +ts-node@^10.4.0, ts-node@>=9.0.0: version "10.9.2" resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== @@ -5240,7 +5332,7 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typescript@5.4.2: +typescript@*, typescript@>=2.7, typescript@5.4.2: version "5.4.2" resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz" integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== @@ -5269,7 +5361,7 @@ unique-slug@^4.0.0: dependencies: imurmurhash "^0.1.4" -unpipe@1.0.0, unpipe@~1.0.0: +unpipe@~1.0.0, unpipe@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -5291,12 +5383,12 @@ unzipper@^0.10.11: setimmediate "~1.0.4" update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + version "1.0.16" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz" + integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.1.2" + picocolors "^1.0.1" uri-js@^4.2.2, uri-js@^4.4.1: version "4.4.1" @@ -5315,21 +5407,26 @@ utils-merge@1.0.1: resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@9.0.1: - version "9.0.1" - resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" - integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== - uuid@^3.0.0: version "3.4.0" resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.0, uuid@^8.3.2: +uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uuid@^8.3.2: version "8.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" @@ -5418,7 +5515,7 @@ wmf@~1.0.1: resolved "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz" integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw== -word-wrap@~1.2.3: +word-wrap@^1.2.5, word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== From 1b1a1d860868193c4796f6b9d602b81336572892 Mon Sep 17 00:00:00 2001 From: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:45:39 +0530 Subject: [PATCH 03/29] mdms config to be taken from devops (#853) --- .../project-factory/src/server/validators/campaignValidators.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/project-factory/src/server/validators/campaignValidators.ts b/health-services/project-factory/src/server/validators/campaignValidators.ts index 8c50b9bcd46..1af1e291eba 100644 --- a/health-services/project-factory/src/server/validators/campaignValidators.ts +++ b/health-services/project-factory/src/server/validators/campaignValidators.ts @@ -951,7 +951,7 @@ async function validateProjectType(request: any, projectType: any, tenantId: any } } const params = { tenantId: tenantId } - const searchResponse: any = await httpRequest(config.host.mdms + "egov-mdms-service/v1/_search", searchBody, params); + const searchResponse: any = await httpRequest(config.host.mdms + config?.paths?.mdms_search, searchBody, params); if (searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes && Array.isArray(searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes)) { const projectTypes = searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; if (!projectTypes.includes(projectType)) { From e3d5238289fcaea3df4ef1a23277fe7c2e59fd9e Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:30:00 +0530 Subject: [PATCH 04/29] HLM service request, updated DataTypeEnum (#872) --- .../egov/servicerequest/web/models/AttributeDefinition.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java index cefb96adac8..59c32cf913b 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java @@ -60,7 +60,9 @@ public enum DataTypeEnum { MULTIVALUELIST("MultiValueList"), - FILE("File"); + FILE("File"), + + BOOLEAN("Boolean"); private String value; From a0e714254ca41e0dc1c1a7130eb89c6edb698df1 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Fri, 30 Aug 2024 13:44:44 +0530 Subject: [PATCH 05/29] Service request changelog 1.5 (#875) * Added changelog and upgraded the versions for household, individual and service request * Update core-services/service-request/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/individual/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * HLM fixed merge issues * HLM fixed merge issues * HCMPRE-413: updated the changelog as per code review comments * Update health-services/project/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- core-services/service-request/CHANGELOG.md | 4 ++++ core-services/service-request/pom.xml | 2 +- health-services/household/CHANGELOG.md | 12 +++++++++--- health-services/household/pom.xml | 2 +- health-services/individual/CHANGELOG.md | 8 +++++--- health-services/individual/pom.xml | 2 +- health-services/project/CHANGELOG.md | 1 + health-services/referralmanagement/CHANGELOG.md | 1 + health-services/stock/CHANGELOG.md | 1 + 9 files changed, 24 insertions(+), 9 deletions(-) diff --git a/core-services/service-request/CHANGELOG.md b/core-services/service-request/CHANGELOG.md index a27826b5875..d1d5607bbd3 100644 --- a/core-services/service-request/CHANGELOG.md +++ b/core-services/service-request/CHANGELOG.md @@ -1,5 +1,9 @@ All notable changes to this module will be documented in this file. +## 1.0.1 - 2024-08-29 + +- Added `BOOLEAN` DataType in `AttributeDefinition` + ## 1.0.0 - Base version \ No newline at end of file diff --git a/core-services/service-request/pom.xml b/core-services/service-request/pom.xml index 3c16fbe8189..5b5bfe71423 100644 --- a/core-services/service-request/pom.xml +++ b/core-services/service-request/pom.xml @@ -4,7 +4,7 @@ service-request jar service-request - 1.0.0 + 1.0.1 1.8 ${java.version} diff --git a/health-services/household/CHANGELOG.md b/health-services/household/CHANGELOG.md index 3eed6ddb78c..3b9cbec0526 100644 --- a/health-services/household/CHANGELOG.md +++ b/health-services/household/CHANGELOG.md @@ -1,7 +1,12 @@ All notable changes to this module will be documented in this file. -## 1.1.3 - 2024-05-29 -- Integrated Core 2.9LTS +## 1.1.4 - 2024-08-29 + +- Added `ExistentEntityValidator` fixes + +## 1.1.3 - 2024-05-29 + +- Integrated Core 2.9 LTS - Client reference ID validation added - Upgraded to health models 1.0.20 and health common 1.0.16 - Boundary v2 Integration @@ -11,8 +16,9 @@ All notable changes to this module will be documented in this file. - Upgraded Flyway-Core to 9.22.3 ## 1.1.2 - 2024-05-10 + - Integrated Boundary v2 functionality -- + ## 1.1.1 - 2023-11-15 - Added total count for household diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 955934b5e1a..798eba22c92 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -5,7 +5,7 @@ household jar household - 1.1.3 + 1.1.4 17 ${java.version} diff --git a/health-services/individual/CHANGELOG.md b/health-services/individual/CHANGELOG.md index 26df13994d2..2ac982c765d 100644 --- a/health-services/individual/CHANGELOG.md +++ b/health-services/individual/CHANGELOG.md @@ -1,7 +1,11 @@ All notable changes to this module will be documented in this file. +## 1.1.6 - 2024-08-29 + + - Added `ExistentEntityValidator` fixes + +## 1.1.5 - 2024-05-29 -## 1.1.5 - 2024-05-29 - Integrated Core 2.9LTS - Client reference ID validation added - Upgraded to health models 1.0.20 and health common 1.0.16 @@ -24,8 +28,6 @@ All notable changes to this module will be documented in this file. - Added proximity based search support -## 1.1.0 - ## 1.0.0 diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index ab7767c7206..84ca10da8d3 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -5,7 +5,7 @@ individual jar individual - 1.1.5 + 1.1.6 17 ${java.version} diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 7865206457c..95369041416 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to this module will be documented in this file. - Upgraded PostgresSQL Driver version to 42.7.1 - Upgraded Flyway base image version to 10.7.1 for DB Migration - Upgraded Flyway-Core to 9.22.3 +- Added `ExistentEntityValidator` fixes ## 1.1.2 - 2024-02-26 - Implemented validation for updating project start date and end date. diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md index 21e78657688..a1f5546b24e 100644 --- a/health-services/referralmanagement/CHANGELOG.md +++ b/health-services/referralmanagement/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this module will be documented in this file. ## 1.0.3 - 2024-08-09 - Upgraded downsync logic. +- Added `ExistentEntityValidator` fixes ## 1.0.2 - 2024-05-29 diff --git a/health-services/stock/CHANGELOG.md b/health-services/stock/CHANGELOG.md index 564823f17b1..de3d5826f7a 100644 --- a/health-services/stock/CHANGELOG.md +++ b/health-services/stock/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this module will be documented in this file. - Upgraded PostgresSQL Driver version to 42.7.1 - Upgraded Flyway base image version to 10.7.1 for DB Migration - Upgraded Flyway-Core to 9.22.3 +- Added `ExistentEntityValidator` fixes ## 1.1.2 - 2024-02-26 - Enhance inventory flow with sender id and receiver id added. From df5b6c9f497d1a7d691d4a59ab2156efedabab19 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 9 Sep 2024 15:00:36 +0530 Subject: [PATCH 06/29] HCMPRE-424: fixed hrms call from pgr-service --- .../src/main/java/org/egov/pgr/util/HRMSUtil.java | 6 ++++-- .../org/egov/pgr/validator/ServiceRequestValidator.java | 4 +++- .../java/org/egov/pgr/web/controllers/MockController.java | 2 +- .../src/main/java/org/egov/pgr/web/models/Workflow.java | 4 ++++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java b/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java index 52416b33f23..724c5ee523f 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java @@ -32,13 +32,15 @@ public HRMSUtil(ServiceRequestRepository serviceRequestRepository, PGRConfigurat /** * Gets the list of department for the given list of uuids of employees + * * @param uuids + * @param employeeUuids * @param requestInfo * @return */ - public List getDepartment(List uuids, RequestInfo requestInfo){ + public List getDepartment(List uuids, List employeeUuids, RequestInfo requestInfo){ - StringBuilder url = getHRMSURI(uuids); + StringBuilder url = getHRMSURI(employeeUuids); RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java b/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java index e6d154759fc..b98a8f90574 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java @@ -159,10 +159,12 @@ private void validateDepartment(ServiceRequest request, Object mdmsData){ String serviceCode = request.getService().getServiceCode(); List assignes = request.getWorkflow().getAssignes(); + List hrmsAssignes = request.getWorkflow().getHrmsAssignes(); + if(CollectionUtils.isEmpty(assignes)) return; - List departments = hrmsUtil.getDepartment(assignes, request.getRequestInfo()); + List departments = hrmsUtil.getDepartment(assignes, hrmsAssignes, request.getRequestInfo()); String jsonPath = MDMS_DEPARTMENT_SEARCH.replace("{SERVICEDEF}",serviceCode); diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java b/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java index 16a32b5a77c..92d32234043 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java @@ -113,7 +113,7 @@ public ResponseEntity requestsUpdatePost() throws IOException { public ResponseEntity> requestsTest(@RequestBody RequestInfoWrapper requestInfoWrapper, @RequestParam String tenantId, @RequestParam List uuids) { - List department = hrmsUtil.getDepartment(uuids, requestInfoWrapper.getRequestInfo()); + List department = hrmsUtil.getDepartment(uuids, uuids, requestInfoWrapper.getRequestInfo()); return new ResponseEntity<>(department, HttpStatus.OK); } diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java b/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java index b1260ba4e41..59b606e0b5e 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java @@ -35,6 +35,10 @@ public class Workflow { @Valid private List assignes = null; + @JsonProperty("hrmsAssignes") + @Valid + private List hrmsAssignes = null; + @SafeHtml @JsonProperty("comments") private String comments = null; From 1aedebd1590e941d3ae0932a07ef522afca7dfc3 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 9 Sep 2024 15:51:00 +0530 Subject: [PATCH 07/29] HCMPRE-424: updated as per code review comments --- .../src/main/java/org/egov/pgr/util/HRMSUtil.java | 4 ++-- .../java/org/egov/pgr/validator/ServiceRequestValidator.java | 2 +- .../src/main/java/org/egov/pgr/web/models/Workflow.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java b/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java index 724c5ee523f..4409e39ed35 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java @@ -33,8 +33,8 @@ public HRMSUtil(ServiceRequestRepository serviceRequestRepository, PGRConfigurat /** * Gets the list of department for the given list of uuids of employees * - * @param uuids - * @param employeeUuids + * @param uuids user uuids + * @param employeeUuids employee uuids * @param requestInfo * @return */ diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java b/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java index b98a8f90574..fe9e1bd148c 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java @@ -159,7 +159,7 @@ private void validateDepartment(ServiceRequest request, Object mdmsData){ String serviceCode = request.getService().getServiceCode(); List assignes = request.getWorkflow().getAssignes(); - List hrmsAssignes = request.getWorkflow().getHrmsAssignes(); + List hrmsAssignes = request.getWorkflow().getHrmsAssignees(); if(CollectionUtils.isEmpty(assignes)) return; diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java b/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java index 59b606e0b5e..eb949bfce25 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java @@ -37,7 +37,7 @@ public class Workflow { @JsonProperty("hrmsAssignes") @Valid - private List hrmsAssignes = null; + private List hrmsAssignees = null; @SafeHtml @JsonProperty("comments") From 12223699de3660534a990059f4c821f58808c628 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:38:03 +0530 Subject: [PATCH 08/29] Create branch-name-validator (#960) * Create branch-name-validator * Update branch-name-validator * Update .github/workflows/branch-name-validator Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/branch-name-validator Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .github/workflows/branch-name-validator | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/branch-name-validator diff --git a/.github/workflows/branch-name-validator b/.github/workflows/branch-name-validator new file mode 100644 index 00000000000..45dd9c4afa4 --- /dev/null +++ b/.github/workflows/branch-name-validator @@ -0,0 +1,36 @@ +name: Enforce Branch Naming Convention + +on: + push: + branches: + - "*" + pull_request: + branches: + - "*" + +jobs: + branch-name-check: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Enforce branch naming convention + run: | + # Get the branch name + branch_name=$(echo "${GITHUB_REF#refs/heads/}") + + # Define the branch name pattern + branch_regex="^(master|develop|(HCMPRE|HCMPOST|HCMSUB)-[0-9]{3,}-[a-zA-Z0-9-]+)$" + + # Check if the branch name matches the pattern + if [[ ! "$branch_name" =~ $branch_regex ]]; then + echo "Branch name '$branch_name' does not follow the required naming convention." + echo "Branch names must follow the pattern: (feature|bugfix|hotfix|release)/PROJ-1234-description" + exit 1 + fi + + - name: Success message + run: | + branch_name=$(echo "${GITHUB_REF#refs/heads/}") + echo "Branch name '$branch_name' follows the required naming convention: 'master', 'develop', or (HCMPRE|HCMPOST|HCMSUB)-123-description" From 08df5e75095be203f1e871c8b4307eee37697012 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:51:05 +0530 Subject: [PATCH 09/29] Update branch-name-validator --- .github/workflows/branch-name-validator | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch-name-validator b/.github/workflows/branch-name-validator index 45dd9c4afa4..d613cfe22d6 100644 --- a/.github/workflows/branch-name-validator +++ b/.github/workflows/branch-name-validator @@ -26,7 +26,7 @@ jobs: # Check if the branch name matches the pattern if [[ ! "$branch_name" =~ $branch_regex ]]; then echo "Branch name '$branch_name' does not follow the required naming convention." - echo "Branch names must follow the pattern: (feature|bugfix|hotfix|release)/PROJ-1234-description" + echo "Branch names must follow the pattern: (HCMPRE|HCMPOST|HCMSUB)-123-description" exit 1 fi From 11a58004afaeb411a8e295e613d33f227eef441d Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:59:43 +0530 Subject: [PATCH 10/29] Rename branch-name-validator to branch-name-validator.yml --- .../{branch-name-validator => branch-name-validator.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{branch-name-validator => branch-name-validator.yml} (100%) diff --git a/.github/workflows/branch-name-validator b/.github/workflows/branch-name-validator.yml similarity index 100% rename from .github/workflows/branch-name-validator rename to .github/workflows/branch-name-validator.yml From 1ad04eed8f19404787c3d77e6f8dd827e8821914 Mon Sep 17 00:00:00 2001 From: tanishi-egov Date: Thu, 17 Oct 2024 11:27:00 +0530 Subject: [PATCH 11/29] Added census-service in build-config (#990) --- build/build-config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index dec24965782..cafec0ff43c 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -259,6 +259,13 @@ config: build: - work-dir: "analytics/auth-proxy" image-name: "auth-proxy" + - name: "builds/health-campaign-services/health-services/census-service" + build: + - work-dir: "health-services/census-service" + image-name: "census-service" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/census-service/src/main/resources/db" + image-name: "census-service-db" # frontend - name: builds/health-campaign-services/frontend/workbench-ui From d4fd0c92a06ef52b41c74f7d4eded1c97ae01b24 Mon Sep 17 00:00:00 2001 From: Palak Garg <86659286+palak-egov@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:01:07 +0530 Subject: [PATCH 12/29] [HCMPRE-658] Refractor resource-estimation-service to resource-generator (#910) Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> --- build/build-config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/build-config.yml b/build/build-config.yml index cafec0ff43c..2002805a366 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -250,10 +250,10 @@ config: dockerfile: "build/17/maven/Dockerfile" - work-dir: "health-services/plan-service/src/main/resources/db" image-name: "plan-service-db" - - name: "builds/health-campaign-services/health-services/resource-estimation-service" + - name: "builds/health-campaign-services/health-services/resource-generator" build: - - work-dir: "health-services/resource-estimation-service" - image-name: "resource-estimation-service" + - work-dir: "health-services/resource-generator" + image-name: "resource-generator" dockerfile: "build/17/maven/Dockerfile" - name: "builds/health-campaign-services/analytics/auth-proxy" build: From c9f5d73e1322b14b5fd7043eb6a02e4838cf06b2 Mon Sep 17 00:00:00 2001 From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Mon, 9 Dec 2024 13:40:29 +0530 Subject: [PATCH 13/29] HCM Admin Console v0.3 Release code changes (#1082) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * kafka fix for large messages * Update genericUtils.ts * Update campaignValidators.ts * Fixed the mdms search path keys * fix of migration script * fix on repeated key * Update campaignApis.ts * Update campaignApis.ts * Update campaignUtils.ts * Update campaignUtils.ts * Update campaignUtils.ts * Fix project target mapping * refactored migration files fro project-factory (#867) * refactored migration files fro project-factory * updated logic for unique username generation * updated format and id name for user name * removed hash logic for username generation * added indexing on columns * updated idgen seq format for user name in index.ts * Update health-services/project-factory/src/server/api/campaignApis.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * updated logic for regenerate if campaign type differs (#876) * id generation throw error update * Enhance generate template for user and facility in update ongoing campaign flow (#885) * commit for update-generate-template * updated campaign flow generate template enhancement * just if else changes * some reformatting * update index.ts * added additional valiadtion for parent campaign * updated logic for validating parent campaign * refcatored as per change requests * update index.ts * updated logic for same campaignnumber when paren is present * updated the campaign name logic along with handling isfailed status too (#888) * updating campaign name same as parent name and number too * updated target template for updating ongoing campaign (#893) * Microplan bulk user creation (#890) * Feat : initialised bulk user creation for microplan * Enhanced user bulk upload for microplan * Fixed configs * Merge fix with console * Feat : added columns in user sheet * Added userroles sheet for bulk user template in microplan * Added source microplan while resource creation * changed logic for isSourceMicroplan * Update campaignApis.ts * Update campaignValidators.ts * changes for campaign update flow * Update campaignUtils.ts * Integrated required error messages * added numeric check in microplan phone number * Implemented no data validation * added logic for creating projects , project facility and project staff on newly added boundaries (#917) * updated target template for updating ongoing campaign * update flow campaign mapping * updated flow campaign mapping * added logic for project, project facility and project staff creation on newly added boundaries * removed one useless func * removed await from a func * removed console.logs * added some minor enhancemnets * added one edge case scenario * changed request limit to 1 mb * Feat : added locksheet filter for user microplan creation * updated logic for regenerate if campaign type differs (#876) * Enhancement for microplan user creation (#940) * some modifications for edge cases (#930) * added commit for testing update campaign flow * some chenages related to type boundary in data create api * /* MODIFIED FOR LTS UPGRADE */ * Microplan user enhancement * Some changes regarding microplan user and boundary * added some null checks * /* Temporay fix for project creation of LLIN since the structure of delivery rules is getting changed */ * Revert "/* MODIFIED FOR LTS UPGRADE */" This reverts commit 52ed7725a515fb3699f76161938add08b48202c0. * added code to add lat long in the project-factory apis * Changed code based on comments * removed default campaignid * added code to add lat long in the project-factory apis (#951) * added code to add lat long in the project-factory apis * Changed code based on comments * removed default campaignid * Fixed code to manage create * fixed the build * added for field protection on sheet data * Facility microplan validation (#975) * Microplan facility validation * Enhancement in microplan validations * Microplan sheet lock * Enhanced for multiple sheetErrors in additionalDetails * Update campaignApis.ts * fixes for filestore and unfreezing boundary code mandatory columns (#984) * Update CODEOWNERS * Update campaignValidators.ts (#987) * some correction of error after changes from microplan code merge (#988) * some correction of error after changes from microplan code merge * added question mark * added localization fix (#993) Co-authored-by: ansh-egov * Update campaignApis.ts (#994) * Added some fixes for the project transformation * Update projectTypeUtils.ts * Update campaignUtils.ts * Removed date Update projectTypeUtils.ts #1006 * HCEMPRE-809-Boundary-geometry-codes (#1011) * added localization fix * added logic for boundaryGeometryManagement * fixed some things * fixed campaign search * update project facility and staff mappings of exisitng facilities and users (#998) * some correction of error after changes from microplan code merge * added logic for updating mapping of existing facilitie and users * resolved comments by jagan on the pr for delinking and linking project resources * fetchProjectsWithBoundaryCodeAndName fucntion update * Update campaignValidators.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * added code to add lat long in the project-factory apis (#1019) * Project staff mapping correction from uuid to userserviceuuid (#1022) * some correction of error after changes from microplan code merge * corrected for mapping of project staff * added changes for project-resource mapping (#1028) * added changes for project-resource mapping * changed the variable name to boundaryProjectMappingForProjectResourceCreation from newBoundaryProjectMapping * renamed the entity --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Added logic to retry in project campaign create (#1031) * not needed to update every resource in update flow (#1036) * not needed to update every resource in update flow * added changes for if boundaries present in update flow all resources are mandate * Some checks enhancement (#1042) * Update genericApis.ts (#1043) * Update campaignValidators.ts (#1046) * consolidate resources array in update campaign flow (#1051) * consolidate resources array in update campaign flow * spelling correct * Search criteria object corrected (#1052) * consolidate resources array in update campaign flow * data search criteria id has to be an array of strings * spelling * some more corrections regarding search criteria body * Boundaries consolidate after creating child campaign (#1056) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * Boundaries correction (#1058) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * changes in extracing boundaries from campaign object * Missing resources in chid campaign to be added from parent camaig logic refactored (#1059) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * refactored logic for adding missing resources from parent campaign * Correction datatocreate column from status to userservice uuids (#1061) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * changed data to create column from user sheet * Hide Boundary and Target Old Columns (#1062) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * hide boundary code old and target old * Corrected target update flow (#1065) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * corrected target mapping in update flow * Total count of Campaigns if only is active true (#1066) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * count will be only of active campaigns * HCMPRE-1212:: migrated to point only to MMDS v2 api * Update index.ts * User/facility inactive (#1070) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * added logic for making exiting user facility inactive --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Refactor facility mappings (#1072) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * refactored facility mappings * Created enity for boundary * updated the boundary relationship function * Update index.ts * fixed some localization issue (#1075) * fixed some localization issue * fixed * Target update while campaign update flow (#1078) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * logic for updating targets * some refactor for adding logs and index.ts * updated the boundary localisation name --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * fixed some localization issue (#1079) * fixed some localization issue * fixed * fixed a issue * reverted failed campaign is active true from false (#1080) * reverted failed campaign is active true from false * took constants from index * refactor * Merge branch 'project-factory-kafka-fix' into console * Changed hierarchyFectch to v2 (#1077) * Changed hierarchyFectch to v2 * Changed messages * Merge branch 'project-factory-kafka-fix' into hierarchyFetchV2 --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * calll generate when create completes for type boundary management * auto generate resource if there is no previous generated history * Fixed crashloop issue (#1084) * Fixed crashloop issue * Update dataManageService.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * changed the master from hierarchyConfig to HierarchySchema (#1086) * getting boundaries split on logic change (#1088) * fixed some localization issue (#1090) * fixed some localization issue * fixed * fixed a issue * integrated microplan with console * fixxed index * fixed crashloop (#1091) * added validation for boundary bulk upload (#1092) Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * refcatored diffferent tab separation (#1093) * added timeout (#1095) * Microplan integration :: set start date to tommorow (#1096) * set start date to tommorow * updated end date * Enhance PlanFacility object (#1099) * validation for update template in create flow (#1100) * removed await (#1103) * some correction (#1104) * logic for updating targets only when present in resources array in update flow (#1105) * updated (#1106) * updated * added fix for the redis error in logs --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * added error responder (#1107) * refactored download api (#1108) * Cache issue fix(#1109) * refactored download api * refactor --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * made disable of cache always during boundary generate (#1110) Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Redis cache key deleted (#1113) * removed await * delete cache from boundary relationship search * updated redis delete func * Revert "removed await" This reverts commit a5acb54c87747f2fa8e53444c0e0af209734b126. * Update redisUtils.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * updated redis delete func (#1114) * removed cache from boundary relation create (#1115) * corrected params of auto generate after download api (#1116) * refactored consolidate (#1119) * fix on the fetch from microplan Update campaignUtils.ts (#1120) * Update microplanUtils.ts (#1123) * addded localization function (#1125) * Update SearchCriteria.ts * made createandtransfrom localization as await to upsert all localization in boundary management create flow (#1127) * added logs in handledropdownthings (#1128) * Fixed district missing issue (#1129) * Facility Village List For microplan and dropdown fix (#1130) * Facility Village List For microplan and dropdown fix * Optional chaining * Reverted recievedDropdown Changes * removed localization caceh in boundary generate flow for hierarchy module (#1133) * planFacility create Fix (#1132) * fixed the localisation cache on multiple data creates in boundary * Revert "fixed the localisation cache on multiple data creates in boundary" This reverts commit 94eb970448b4264888e589074c6292a5066222d3. * Facility fix generation for microplan (#1134) * planFacility create Fix * Fixed Facility Generation for microplan * added the count info of the localisation upsert (#1144) Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Microplan integrated with console for facility , user & target (#1151) * set start date to tommorow * updated end date * added code for target sheet * fixed * added mdms call * microplan integration changes added for target ,facility & user * undo changes * Update microplanIntergration.ts * saving all the progress on the integration * project facility mapping done * Update microplanIntergration.ts * Update microplanIntergration.ts * Update microplanIntergration.ts * target & facility integration completed statically * completed facility & target file created based on microplan * added static for user * Added user related changes * added the user integartion * added target and facility in resources array of campaign from microplan * added user in resources array in campaign object * Update microplanIntergration.ts * revert the others * Update index.ts * Cleaned up code --------- Co-authored-by: ansh-egov Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: nitish-egov * added missing default tenantid (#1152) * Boundary locale fix (#1153) * planFacility create Fix * Fixed boundary validation for different locales --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * removed duplicate key (#1154) * Logs for reordering added (#1161) * added missing default tenantid * added logs for reordering before project creation * Update index.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Readme for microplans (#1160) * Readme for microplans * Fixed boolean type * Optimized isMicroplanRequest * Optimizing roles for microplan (#1164) * Improved some performance with huge campaign object (#1165) * Trying optimised code by chatgpt * added 4mb limit * Update app.ts * Updted the comments * Changes for pollutils and reorder * Update pollUtils.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: ashish-egov * Added fixes for error during processing (#1172) * added missing default tenantid * added try catch * Update index.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * fixed the hard codings in the code (#1170) * fixed the hard codings in the code * fixed * Added filter check for the fetch from microplan if it has already some resources * fixed hardcoding in target flow (#1175) * fixed hardcoding in target flow * fixed * fixed * Update campaignApis.ts (#1177) * Update campaignApis.ts * Update campaignApis.ts * Update campaignApis.ts * Update genericUtils.ts (#1178) * changed the campaig key to activity (#1180) * added missing default tenantid * Update campaignUtils.ts * Update index.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * handled failed generations in downlaod api (#1185) * Change for roles name change (#1187) * added search before update in fetch all datas (#1190) * added seacrh before update in fetch all datas * Change for roles name change (#1187) --------- Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * formatted and made promise all to do a promise all to make calls parallely * filtered the plan facility response to have only facility which has only service boundarires * added hierarchy filteration from mdms (#1188) * added hierarchy filteration from mdms * did some hardcoding * fixed fetching of headers * added some logs * added extra loggers for fetch from microplan activities (#1193) * added extra loggers for fetch from microplan activities * Update microplanIntergration.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * added retry in localization upsert (#1194) * Adding the additonal loggers to know more informs on microplan integration * Update health-services/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fixed integration (#1197) * Global handler (#1199) * Change for roles name change * Global exception handler integrated * String logger * Update app.ts * added heap memory log & created a env variable for incomingRequestPay… …loadLimit (#1201) * added heap memory log & created a env variable for incomingRequestPayloadLimit * Update index.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Set memory limit and added log off avaiable, max limits (#1202) * added logs to check current value * Update app.ts * Update Dockerfile * Update Dockerfile * Update app.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Handle for google sheet formulas (#1207) * Update microplanValidators.ts (#1213) * Update microplanValidators.ts * Update microplanValidators.ts * Update microplanValidators.ts * Localised roles (#1217) * added change log for admin console version 0.3 (#1224) * Pvar validation (#1225) * product variant validation added * Optimized validations * Refactored * Logger error fix * Refactor * Refactor * refactored project reosurce mapping logic (#1204) * refactored project reosurce mapping logic * added new function ot search project after campaign creation time * added reference id params in project search * added logic for adding resources only for newly created projects * refactored and code clean up for project resource mapppings in update and create flow * refactor getProjectMappingBody func * some condition check * correction * removed project departments * microplan save topic changes (#1231) * Update microplanUtils.ts * Update index.ts * Update campaignApis.ts (#1232) * Update campaignApis.ts * Update campaignApis.ts * Update campaignApis.ts * Update campaignValidators.ts * Revert boundaryProject Mapping * Cleaned up data configs (#1234) * Update index.ts * Update campaignUtils.ts * Update health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update app.ts * Update health-services/project-factory/src/server/utils/microplanUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * added changes for performance testing (#1236) * added changes for performance testing * microplan save topic changes (#1231) * Update microplanUtils.ts * Update index.ts * Update campaignApis.ts (#1232) * Update campaignApis.ts * Update campaignApis.ts * Update campaignApis.ts * Update campaignValidators.ts * Revert boundaryProject Mapping * Cleaned up data configs (#1234) * Update index.ts * Update campaignUtils.ts * try catch handling * Update health-services/project-factory/src/server/service/dataManageService.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: ansh-egov <137172017+ansh-egov@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update app.ts * Update health-services/project-factory/src/server/utils/microplanUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update campaignValidators.ts (#1244) * Update campaignValidators.ts * Update campaignValidators.ts * add * added new config values * Other configs (#1250) * add * added new config values * Update request.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Updating debug function for error handeling (#1243) * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/project-factory/src/server/service/dataManageService.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update dataManageService.ts * Applied code rabbit changes * refactored sheet consolidate logic (#1254) * refactored sheet consolidate logic * Applied code rabbit changes --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * refactor sheet consolidate for target (#1255) * Update package.json * Update health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * removed other ui workflows * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Update publishProjectFactory.yml * consolidate sheet handle logic change (#1256) * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: ashish-egov Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: nitish-egov Co-authored-by: ansh-egov Co-authored-by: ansh-egov <137172017+ansh-egov@users.noreply.github.com> Co-authored-by: ejagankumar <31833516+ejagankumar@users.noreply.github.com> --- .github/workflows/buildWorkbenchUI.yml | 64 - .github/workflows/publishAllPackages.yml | 25 - .../workflows/publishAllPackagesRelease.yml | 20 - .github/workflows/publishProjectFactory.yml | 115 +- CODEOWNERS | 4 +- health-services/project-factory/CHANGELOG.md | 6 + health-services/project-factory/Dockerfile | 4 +- .../V20240315110400__resource_details_ddl.sql | 46 - .../V20240315110513__campaign_details_ddl.sql | 16 - ...01154500__campaign_details_add_columns.sql | 3 - ...2134500__campaign_details_alter_column.sql | 2 - ...0154500__campaign_details_alter_column.sql | 3 - .../V20240416170000__generate_add_column.sql | 2 - .../V20240427174100__campaign_add_column.sql | 2 - ...2143500__resource_details_alter_column.sql | 2 - ...enerated_resource_details_alter_column.sql | 13 - .../V20240625141100__process_details_ddl.sql | 11 - ...generated_resource_detail_alter_column.sql | 24 - ...100__remove_constraint_process_details.sql | 3 - ...__add_uniqiue_constraint_process_track.sql | 10 - ...40826145500__add_resource_and_campaign.sql | 92 + .../V20240829125000__add_index_on_tables.sql | 5 + ...rentid_isactive_in_eg_campaign_details.sql | 5 + ...remove_campaign_name_unique_constraint.sql | 2 + ...241013115000__add_hierarchytype_column.sql | 1 + .../project-factory/package-lock.json | 1389 ++--- health-services/project-factory/package.json | 4 +- .../src/server/api/campaignApis.ts | 1742 ++++-- .../src/server/api/coreApis.ts | 259 + .../src/server/api/genericApis.ts | 416 +- .../src/server/api/healthApis.ts | 28 + .../src/server/api/microplanApis.ts | 124 + .../project-factory/src/server/app.ts | 90 +- .../src/server/config/constants.ts | 19 +- .../src/server/config/createAndSearch.ts | 23 +- .../src/server/config/index.ts | 53 +- .../server/config/models/SearchCriteria.ts | 3 + .../models/campaignDetailsDraftSchema.ts | 5 +- .../config/models/createRequestSchema.ts | 5 +- .../config/models/downloadRequestSchema.ts | 4 +- .../config/models/generateRequestSchema.ts | 7 +- .../config/models/searchCampaignDetails.ts | 3 + .../campaignManage.controller.ts | 52 +- .../localisation.controller.ts | 33 +- .../src/server/kafka/Producer.ts | 45 +- .../src/server/models/Boundary.d.ts | 115 + .../src/server/models/MDMS.d.ts | 144 + .../src/server/models/index.ts | 8 + .../server/service/campaignManageService.ts | 40 +- .../src/server/service/dataManageService.ts | 56 +- .../utils/boundariesConsolidationUtils.ts | 44 + .../src/server/utils/boundaryUtils.ts | 53 + .../src/server/utils/campaignMappingUtils.ts | 362 +- .../src/server/utils/campaignUtils.ts | 5215 +++++++++++------ .../src/server/utils/excelUtils.ts | 94 +- .../src/server/utils/generateUtils.ts | 33 +- .../src/server/utils/genericUtils.ts | 454 +- .../src/server/utils/logger/index.ts | 19 +- .../src/server/utils/microplanIntergration.ts | 985 ++++ .../src/server/utils/microplanUtils.ts | 494 ++ .../utils/onGoingCampaignUpdateUtils.ts | 781 +++ .../src/server/utils/pollUtils.ts | 193 + .../src/server/utils/redisUtils.ts | 52 +- .../src/server/utils/request.ts | 40 +- .../src/server/utils/targetUtils.ts | 2 +- .../localisationMessageConstructor.ts | 116 +- .../utils/transforms/projectTypeUtils.ts | 67 +- .../transforms/searchResponseConstructor.ts | 2 + .../server/validators/campaignValidators.ts | 815 ++- .../src/server/validators/genericValidator.ts | 22 +- .../server/validators/microplanValidators.ts | 300 + health-services/project-factory/yarn.lock | 2572 ++++---- 72 files changed, 12697 insertions(+), 5165 deletions(-) delete mode 100644 .github/workflows/buildWorkbenchUI.yml delete mode 100644 .github/workflows/publishAllPackages.yml delete mode 100644 .github/workflows/publishAllPackagesRelease.yml delete mode 100644 health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql delete mode 100644 health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql delete mode 100644 health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql delete mode 100644 health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql delete mode 100644 health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql delete mode 100644 health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql delete mode 100644 health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql delete mode 100644 health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql delete mode 100644 health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql delete mode 100644 health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql delete mode 100644 health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql delete mode 100644 health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql delete mode 100644 health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql create mode 100644 health-services/project-factory/migration/main/V20240826145500__add_resource_and_campaign.sql create mode 100644 health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql create mode 100644 health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql create mode 100644 health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql create mode 100644 health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql create mode 100644 health-services/project-factory/src/server/api/coreApis.ts create mode 100644 health-services/project-factory/src/server/api/healthApis.ts create mode 100644 health-services/project-factory/src/server/api/microplanApis.ts create mode 100644 health-services/project-factory/src/server/models/Boundary.d.ts create mode 100644 health-services/project-factory/src/server/models/MDMS.d.ts create mode 100644 health-services/project-factory/src/server/models/index.ts create mode 100644 health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts create mode 100644 health-services/project-factory/src/server/utils/microplanIntergration.ts create mode 100644 health-services/project-factory/src/server/utils/microplanUtils.ts create mode 100644 health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts create mode 100644 health-services/project-factory/src/server/utils/pollUtils.ts create mode 100644 health-services/project-factory/src/server/validators/microplanValidators.ts diff --git a/.github/workflows/buildWorkbenchUI.yml b/.github/workflows/buildWorkbenchUI.yml deleted file mode 100644 index 1a0c526d1bf..00000000000 --- a/.github/workflows/buildWorkbenchUI.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Digit Admin Console Build workflow -on: - push: - branches: - - campaign - paths: - - 'micro-ui/web/micro-ui-internals/**' - pull_request: - branches: - - campaign - workflow_dispatch: -jobs: - docker_image-build: - outputs: - run_job_digit_ui: ${{ steps.check_files.outputs.run_job_digit_ui }} - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 - with: - fetch-depth: 2 - - name: Setup Docker - uses: docker/setup-buildx-action@v1 - - name: check modified files - id: check_files - run: | - echo "=============== list modified files ===============" - git diff --name-only HEAD^ HEAD - - echo "========== check paths of modified files ==========" - git diff --name-only HEAD^ HEAD > files.txt - run_job_digit_ui=false - while IFS= read -r file - do - if [[ $file == micro-ui/* ]]; then - echo "This modified file is under the 'digit_ui' folder." - run_job_digit_ui=true - fi - done < files.txt - - # Set the output based on whether the job should run - echo "::set-output name=run_job_digit_ui::$run_job_digit_ui" - echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - echo "COMMIT_ID=${GITHUB_SHA: -8}" >> $GITHUB_ENV # Extract last 8 characters of SHA - echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV - - - - - - name: Login to egovio docker Container Registry - env: - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - run: | - # Authenticate with Docker Hub - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin - - - name: Build and Push Docker image for digit-ui - if: ${{ steps.check_files.outputs.run_job_digit_ui == 'true' }} - run: | - docker build -t workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} -f web/workbench/Dockerfile . - docker tag workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} - docker push egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} - working-directory: micro-ui diff --git a/.github/workflows/publishAllPackages.yml b/.github/workflows/publishAllPackages.yml deleted file mode 100644 index 6bb4b51d612..00000000000 --- a/.github/workflows/publishAllPackages.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Node.js Publish UI Packages - -on: - push: - branches: [ 'develop','campaign' ] - paths: - - 'micro-ui/web/micro-ui-internals/**' - - pull_request: - branches: - - 'dev-hcm' - # Push events to branches matching refs/heads/mona/octocat - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - with: - node-version: 14 - registry-url: https://registry.npmjs.org/ - - run: cd micro-ui/web/micro-ui-internals/ && bash ./publish-develop.sh - env: - NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/publishAllPackagesRelease.yml b/.github/workflows/publishAllPackagesRelease.yml deleted file mode 100644 index ff9b6a3a93f..00000000000 --- a/.github/workflows/publishAllPackagesRelease.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Node.js Publish UI Packages - -on: - push: - branches: [ 'master' ] - paths: - - 'micro-ui/web/micro-ui-internals/**' - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - with: - node-version: 14 - registry-url: https://registry.npmjs.org/ - - run: cd micro-ui/web/micro-ui-internals/ && bash ./publish.sh - env: - NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/publishProjectFactory.yml b/.github/workflows/publishProjectFactory.yml index 19fde98c7ab..33e224b222c 100644 --- a/.github/workflows/publishProjectFactory.yml +++ b/.github/workflows/publishProjectFactory.yml @@ -1,77 +1,72 @@ -name: project factory service docker Image CI +name: Project Factory Service Test Builder on: push: - branches: [ "campaign" ] + branches: + - "console" + - "master" paths: - - 'utilities/project-factory/**' + - 'health-services/project-factory/**' pull_request: - branches: [ "campaign" ] + branches: + - "console" + - "master" jobs: - build: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # Fetch all history for tags and branches + # Step 1: Checkout the repository + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # Fetch all history for tags and branches - - name: Set up environment variables - id: env - run: | - echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV - echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - echo "COMMIT_ID=${GITHUB_SHA: -8}" >> $GITHUB_ENV # Extract last 8 characters of SHA + # Step 2: Set up environment variables + - name: Set up environment variables + id: env + run: | + echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - - name: Build the service Docker image - id: docker_build - working-directory: ./utilities/project-factory - run: | - IMAGE_TAG=egovio/project-factory:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} - docker build . \ - --file Dockerfile \ - --tag $IMAGE_TAG - echo "::set-output name=image_name::$IMAGE_TAG" + # Step 3: Build the service Docker image + - name: Build the service Docker image + id: docker_build + working-directory: ./health-services/project-factory + run: | + IMAGE_TAG=egovio/project-factory:${{ env.ACTION_NUMBER }} + docker build . \ + --file Dockerfile \ + --tag $IMAGE_TAG + echo "::set-output name=image_name::$IMAGE_TAG" + echo "Service Docker image built successfully" + # Step 4: Build the database migration Docker image + - name: Build the DB migration Docker image + id: docker_db_build + working-directory: ./health-services/project-factory/migration + run: | + IMAGE_TAG=egovio/project-factory-db:${{ env.ACTION_NUMBER }} + docker build . \ + --file Dockerfile \ + --tag $IMAGE_TAG + echo "::set-output name=db_image_name::$IMAGE_TAG" + echo "DB migration Docker image built successfully" - - name: Build the db migration Docker image - id: docker_db_build - working-directory: ./utilities/project-factory/migration - run: | - IMAGE_TAG=egovio/project-factory-db:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} - docker build . \ - --file Dockerfile \ - --tag $IMAGE_TAG - echo "::set-output name=db_image_name::$IMAGE_TAG" + node_build: + runs-on: ubuntu-latest + + steps: + # Step 1: Checkout the repository + - uses: actions/checkout@v3 + # Step 2: Set up Node.js environment + - uses: actions/setup-node@v2 + with: + node-version: 20 - - name: Login to Docker Hub and Push Docker Image - working-directory: ./utilities/project-factory - env: - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - IMAGE_NAME: ${{ steps.docker_build.outputs.image_name }} - run: | - # Authenticate with Docker Hub - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin - - # Push the image to Docker Hub - docker push $IMAGE_NAME - echo "Docker image pushed: $IMAGE_NAME" - - - name: Login to Docker Hub and Push DB Migration Docker Image - working-directory: ./utilities/project-factory/migration - env: - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - DB_IMAGE_NAME: ${{ steps.docker_db_build.outputs.db_image_name }} - run: | - # Authenticate with Docker Hub - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin - - # Push the image to Docker Hub - docker push $DB_IMAGE_NAME - echo "Docker image pushed: $DB_IMAGE_NAME" + # Step 3: Install dependencies and build for production + - name: Install dependencies and build + working-directory: ./health-services/project-factory + run: | + yarn install + yarn build diff --git a/CODEOWNERS b/CODEOWNERS index e5b57cd157d..30885762527 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1,3 @@ -* @kavi-egov @sathishp-eGov \ No newline at end of file +* @kavi-egov @sathishp-eGov + +health-services/project-factory/ @jagankumar-egov diff --git a/health-services/project-factory/CHANGELOG.md b/health-services/project-factory/CHANGELOG.md index 8781f319963..47034044d78 100644 --- a/health-services/project-factory/CHANGELOG.md +++ b/health-services/project-factory/CHANGELOG.md @@ -14,3 +14,9 @@ All notable changes to this module will be documented in this file. 1. Timeline integration for workflow of campaign. 2. Call user, facility and boundary generate when boundaries changed in campaign update flow 3. Generate target template based on delivery conditions changed to anything from default. + +## 0.3.0 - 2024-12-03 + 1. Campaign Details Table Updates -> added new columns: parentId and active,removed unique constraint on campaignName. + 2. Update Ongoing Campaign (can add new boundaries , edit facilities , user and target sheet). + 3. Boundary Management Apis added. + 4. Microplan Integration api (fetch-from-microplan api) added. diff --git a/health-services/project-factory/Dockerfile b/health-services/project-factory/Dockerfile index 124ed02c197..0406e6006f1 100644 --- a/health-services/project-factory/Dockerfile +++ b/health-services/project-factory/Dockerfile @@ -13,6 +13,7 @@ ARG COMMIT_ID ENV BRANCH_NAME=$BRANCH_NAME ENV ACTION_NUMBER=$ACTION_NUMBER ENV COMMIT_ID=$COMMIT_ID +ENV NODE_OPTIONS="--max-old-space-size=2048" # Copy package.json and yarn.lock (if exists) COPY package.json ./ @@ -30,5 +31,6 @@ COPY . . EXPOSE 3000 CMD ["yarn", "prod"] - # Replace "app.js" with your entry point file + # Replaced by CMD ["yarn", "prod"] + diff --git a/health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql b/health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql deleted file mode 100644 index aecfae20001..00000000000 --- a/health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql +++ /dev/null @@ -1,46 +0,0 @@ -CREATE TABLE eg_cm_resource_details ( - id varchar(128) PRIMARY KEY, - "status" varchar(128) NOT NULL, - tenantId varchar(128) NOT NULL, - fileStoreId varchar(128) NOT NULL, - processedFileStoreId varchar(128), - "action" varchar(128) NOT NULL, - "type" varchar(64) NOT NULL, - createdBy varchar(128) NOT NULL, - createdTime bigint NOT NULL, - lastModifiedBy varchar(128), - lastModifiedTime bigint, - additionalDetails jsonb -); - -CREATE TABLE eg_cm_resource_activity ( - id varchar(128) PRIMARY KEY, - retryCount integer, - "type" varchar(64), - "url" varchar(128), - requestPayload jsonb, - tenantId varchar(128) NOT NULL, - responsePayload jsonb, - "status" bigint, - createdBy varchar(128), - createdTime bigint, - lastModifiedBy varchar(128), - lastModifiedTime bigint, - additionalDetails jsonb, - resourceDetailsId varchar(128), - FOREIGN KEY (resourceDetailsId) REFERENCES eg_cm_resource_details(id) -); - -CREATE TABLE eg_cm_generated_resource_details ( - id varchar(128) PRIMARY KEY, - fileStoreId varchar(128), - "status" varchar(128), - "type" varchar(128), - tenantid varchar(128), - count bigint, - createdBy varchar(128), - createdTime bigint, - lastModifiedBy varchar(128), - lastModifiedTime bigint, - additionalDetails jsonb -); diff --git a/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql b/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql deleted file mode 100644 index 1f6426149f5..00000000000 --- a/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE eg_cm_campaign_details ( - id character varying(128) PRIMARY KEY, - tenantId character varying(64) NOT NULL, - "status" character varying(128) NOT NULL, - "action" character varying(64) NOT NULL, - campaignNumber character varying(128) NOT NULL, - hierarchyType character varying(128) NOT NULL, - boundaryCode character varying(64), - projectId character varying(128), - createdBy character varying(128) NOT NULL, - lastModifiedBy character varying(128), - createdTime bigint NOT NULL, - lastModifiedTime bigint, - additionalDetails jsonb, - campaignDetails jsonb -); diff --git a/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql b/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql deleted file mode 100644 index eaf0c681333..00000000000 --- a/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE eg_cm_campaign_details -ADD COLUMN campaignName character varying(128) UNIQUE, -ADD COLUMN projectType character varying(128); diff --git a/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql b/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql deleted file mode 100644 index 7a49127c9dd..00000000000 --- a/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE eg_cm_campaign_details -ALTER COLUMN hierarchyType DROP NOT NULL; diff --git a/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql b/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql deleted file mode 100644 index 05dfea2b5c7..00000000000 --- a/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE eg_cm_campaign_details -ADD COLUMN startDate bigint, -ADD COLUMN endDate bigint; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql b/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql deleted file mode 100644 index c96caaa0e5f..00000000000 --- a/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE eg_cm_generated_resource_details -ADD COLUMN hierarchyType varchar(128); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql b/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql deleted file mode 100644 index 36707083732..00000000000 --- a/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE eg_cm_campaign_details -ALTER COLUMN campaignName TYPE character varying(250); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql b/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql deleted file mode 100644 index 25fc10438f1..00000000000 --- a/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE eg_cm_resource_details -ADD COLUMN campaignId character varying(128); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql b/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql deleted file mode 100644 index dfd13713c78..00000000000 --- a/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql +++ /dev/null @@ -1,13 +0,0 @@ -DO $$ -DECLARE - table_name1 TEXT := 'eg_cm_generated_resource_details'; - column_name1 TEXT := 'campaignId'; -BEGIN - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = table_name1 - AND column_name = column_name1 - ) THEN - EXECUTE format('ALTER TABLE %I ADD COLUMN %I character varying(128);', table_name1, column_name1); - END IF; -END $$; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql b/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql deleted file mode 100644 index e7b4037bd8d..00000000000 --- a/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql +++ /dev/null @@ -1,11 +0,0 @@ -CREATE TABLE health.eg_cm_campaign_process ( - id VARCHAR(128) PRIMARY KEY, - campaignId VARCHAR(128) NOT NULL, - type VARCHAR(128), - status VARCHAR(128), - details JSONB, - createdtime BIGINT, - lastmodifiedtime BIGINT, - additionaldetails JSONB, - CONSTRAINT fk_campaignId FOREIGN KEY (campaignId) REFERENCES health.eg_cm_campaign_details(id) -); diff --git a/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql b/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql deleted file mode 100644 index a67a8061f42..00000000000 --- a/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql +++ /dev/null @@ -1,24 +0,0 @@ -DO $$ -DECLARE - table_name1 TEXT := 'eg_cm_generated_resource_details'; - column_name1 TEXT := 'campaignId'; - column_name2 TEXT := 'campaignid'; -BEGIN - -- Check if "campaignId" column exists and drop it if it does - IF EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = table_name1 - AND column_name = column_name1 - ) THEN - EXECUTE format('ALTER TABLE %I DROP COLUMN %I;', table_name1, column_name1); - END IF; - - -- Check if "campaignid" column exists (case-insensitive) and create it if it doesn't - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = table_name1 - AND lower(column_name) = lower(column_name2) - ) THEN - EXECUTE format('ALTER TABLE %I ADD COLUMN %I character varying(128);', table_name1, column_name2); - END IF; -END $$; diff --git a/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql b/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql deleted file mode 100644 index 9142fc152e0..00000000000 --- a/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql +++ /dev/null @@ -1,3 +0,0 @@ --- Migration script to remove the foreign key constraint -ALTER TABLE eg_cm_campaign_process DROP CONSTRAINT IF EXISTS fk_campaignId; -ALTER TABLE eg_cm_resource_activity DROP CONSTRAINT IF EXISTS eg_cm_resource_activity_resourceDetailsId_fkey; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql b/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql deleted file mode 100644 index d9bfbd0af53..00000000000 --- a/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql +++ /dev/null @@ -1,10 +0,0 @@ --- Step 1: Remove duplicate rows -DELETE FROM eg_cm_campaign_process a -USING health.eg_cm_campaign_process b -WHERE a.id < b.id -AND a.campaignId = b.campaignId -AND a.type = b.type; - --- Step 2: Add the unique constraint -ALTER TABLE eg_cm_campaign_process -ADD CONSTRAINT uq_campaignId_type UNIQUE (campaignId, type); diff --git a/health-services/project-factory/migration/main/V20240826145500__add_resource_and_campaign.sql b/health-services/project-factory/migration/main/V20240826145500__add_resource_and_campaign.sql new file mode 100644 index 00000000000..09165a225d3 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240826145500__add_resource_and_campaign.sql @@ -0,0 +1,92 @@ +CREATE TABLE eg_cm_campaign_details +( + id character varying(128) NOT NULL, + tenantid character varying(64) NOT NULL, + status character varying(128) NOT NULL, + action character varying(64) NOT NULL, + campaignnumber character varying(128) NOT NULL, + hierarchytype character varying(128), + boundarycode character varying(64), + projectid character varying(128), + createdby character varying(128) NOT NULL, + lastmodifiedby character varying(128), + createdtime bigint NOT NULL, + lastmodifiedtime bigint, + additionaldetails jsonb, + campaigndetails jsonb, + campaignname character varying(250), + projecttype character varying(128), + startdate bigint, + enddate bigint, + CONSTRAINT eg_cm_campaign_details_pkey PRIMARY KEY (id), + CONSTRAINT eg_cm_campaign_details_campaignname_key UNIQUE (campaignname) +); + +CREATE TABLE eg_cm_campaign_process +( + id character varying(128) NOT NULL, + campaignid character varying(128) NOT NULL, + type character varying(128), + status character varying(128), + details jsonb, + createdtime bigint, + lastmodifiedtime bigint, + additionaldetails jsonb, + CONSTRAINT eg_cm_campaign_process_pkey PRIMARY KEY (id), + CONSTRAINT uq_campaignid_type UNIQUE (campaignid, type) +); + +CREATE TABLE eg_cm_generated_resource_details +( + id character varying(128) NOT NULL, + filestoreid character varying(128), + status character varying(128), + type character varying(128), + tenantid character varying(128), + count bigint, + createdby character varying(128), + createdtime bigint, + lastmodifiedby character varying(128), + lastmodifiedtime bigint, + additionaldetails jsonb, + hierarchytype character varying(128), + campaignid character varying(128), + CONSTRAINT eg_cm_generated_resource_details_pkey PRIMARY KEY (id) +); + +CREATE TABLE eg_cm_resource_activity +( + id character varying(128) NOT NULL, + retrycount integer, + type character varying(64), + url character varying(128), + requestpayload jsonb, + tenantid character varying(128) NOT NULL, + responsepayload jsonb, + status bigint, + createdby character varying(128), + createdtime bigint, + lastmodifiedby character varying(128), + lastmodifiedtime bigint, + additionaldetails jsonb, + resourcedetailsid character varying(128), + CONSTRAINT eg_cm_resource_activity_pkey PRIMARY KEY (id) +); + +CREATE TABLE eg_cm_resource_details +( + id character varying(128) NOT NULL, + status character varying(128) NOT NULL, + tenantid character varying(128) NOT NULL, + filestoreid character varying(128) NOT NULL, + processedfilestoreid character varying(128), + action character varying(128) NOT NULL, + type character varying(64) NOT NULL, + createdby character varying(128) NOT NULL, + createdtime bigint NOT NULL, + lastmodifiedby character varying(128), + lastmodifiedtime bigint, + additionaldetails jsonb, + campaignid character varying(128), + CONSTRAINT eg_cm_resource_details_pkey PRIMARY KEY (id) +); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql b/health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql new file mode 100644 index 00000000000..59df89af11c --- /dev/null +++ b/health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql @@ -0,0 +1,5 @@ +CREATE INDEX idx_eg_cm_campaign_details_status ON eg_cm_campaign_details(status); +CREATE INDEX idx_eg_cm_campaign_details_campaignname ON eg_cm_campaign_details(campaignname); +CREATE INDEX idx_eg_cm_campaign_process_campaignid ON eg_cm_campaign_process(campaignid); +CREATE INDEX idx_eg_cm_generated_resource_details_campaignid ON eg_cm_generated_resource_details(campaignid); +CREATE INDEX idx_eg_cm_resource_details_campaignid ON eg_cm_resource_details(campaignid); diff --git a/health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql b/health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql new file mode 100644 index 00000000000..6ce6b0f771e --- /dev/null +++ b/health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql @@ -0,0 +1,5 @@ +ALTER TABLE eg_cm_campaign_details +ADD COLUMN parentid character varying(128); + +ALTER TABLE eg_cm_campaign_details +ADD COLUMN isactive boolean; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql b/health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql new file mode 100644 index 00000000000..34aa7b31978 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_campaign_details +DROP CONSTRAINT eg_cm_campaign_details_campaignname_key; diff --git a/health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql b/health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql new file mode 100644 index 00000000000..e44468f1cc5 --- /dev/null +++ b/health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql @@ -0,0 +1 @@ +ALTER TABLE eg_cm_resource_details ADD COLUMN hierarchytype character varying(128); \ No newline at end of file diff --git a/health-services/project-factory/package-lock.json b/health-services/project-factory/package-lock.json index a7479aa962a..c13d8382b36 100644 --- a/health-services/project-factory/package-lock.json +++ b/health-services/project-factory/package-lock.json @@ -1,19 +1,19 @@ { "name": "project-factory", - "version": "0.0.1", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "project-factory", - "version": "0.0.1", + "version": "0.2.0", "license": "MIT", "dependencies": { "ajv-errors": "^3.0.0", "axios": "1.6.8", "body-parser": "^1.20.2", "compression": "1.7.4", - "exceljs": "4.4.0", + "exceljs": "^4.4.0", "express": "^4.19.2", "hash-sum": "2.0.0", "helmet": "7.1.0", @@ -69,12 +69,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.24.2", + "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" }, "engines": { @@ -82,30 +82,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", - "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", - "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.24.5", - "@babel/helpers": "^7.24.5", - "@babel/parser": "^7.24.5", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.5", - "@babel/types": "^7.24.5", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -121,9 +121,9 @@ } }, "node_modules/@babel/core/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -153,12 +153,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", - "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "dev": true, "dependencies": { - "@babel/types": "^7.24.5", + "@babel/types": "^7.25.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -168,14 +168,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -207,63 +207,29 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", - "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.0" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", - "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.24.3", - "@babel/helper-simple-access": "^7.24.5", - "@babel/helper-split-export-declaration": "^7.24.5", - "@babel/helper-validator-identifier": "^7.24.5" + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -273,86 +239,74 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz", - "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", - "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", - "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, "dependencies": { - "@babel/types": "^7.24.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", - "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", - "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", - "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", "dev": true, "dependencies": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.5", - "@babel/types": "^7.24.5" + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", - "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -424,10 +378,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", - "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", "dev": true, + "dependencies": { + "@babel/types": "^7.25.2" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -496,12 +453,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", - "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -598,12 +555,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", - "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -613,33 +570,30 @@ } }, "node_modules/@babel/template": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", - "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.24.5", - "@babel/parser": "^7.24.5", - "@babel/types": "^7.24.5", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -648,9 +602,9 @@ } }, "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -680,13 +634,13 @@ "dev": true }, "node_modules/@babel/types": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", - "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.24.1", - "@babel/helper-validator-identifier": "^7.24.5", + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -777,9 +731,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -1159,27 +1113,6 @@ "node": ">=8" } }, - "node_modules/@jest/reporters/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@jest/reporters/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -1324,9 +1257,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { @@ -1366,9 +1299,9 @@ } }, "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -1466,9 +1399,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" @@ -1515,9 +1448,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", - "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", "dev": true, "dependencies": { "@types/node": "*", @@ -1557,9 +1490,9 @@ "dev": true }, "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "dependencies": { "@types/node": "*" } @@ -1574,6 +1507,14 @@ "http-proxy-middleware": "*" } }, + "node_modules/@types/http-proxy/node_modules/@types/node": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", + "dependencies": { + "undici-types": "~6.13.0" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -1620,9 +1561,9 @@ } }, "node_modules/@types/lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==", + "version": "4.17.7", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", + "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", "dev": true }, "node_modules/@types/mime": { @@ -1644,10 +1585,17 @@ "version": "20.11.29", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz", "integrity": "sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA==", + "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, + "node_modules/@types/node/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/@types/pg": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.3.tgz", @@ -1732,9 +1680,9 @@ } }, "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -1788,10 +1736,25 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk/node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, + "bin": { + "acorn": "bin/acorn" + }, "engines": { "node": ">=0.4.0" } @@ -1816,9 +1779,9 @@ } }, "node_modules/agent-base/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -1849,14 +1812,14 @@ } }, "node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -1991,67 +1954,18 @@ "node": ">= 6" } }, - "node_modules/archiver-utils/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/archiver/node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/archiver/node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/archiver/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "node_modules/are-we-there-yet": { @@ -2065,6 +1979,21 @@ "readable-stream": "^2.0.6" } }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "optional": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -2101,12 +2030,9 @@ } }, "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, "node_modules/asynckit": { "version": "0.4.0", @@ -2322,12 +2248,13 @@ "dev": true }, "node_modules/bl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", - "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, "node_modules/bluebird": { @@ -2368,20 +2295,20 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "dev": true, "funding": [ { @@ -2398,10 +2325,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -2494,6 +2421,14 @@ "long": "1.1.2" } }, + "node_modules/buffermaker/node_modules/long": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/long/-/long-1.1.2.tgz", + "integrity": "sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", @@ -2525,9 +2460,9 @@ } }, "node_modules/cacache": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", - "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", + "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -2546,6 +2481,47 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -2583,9 +2559,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001620", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz", - "integrity": "sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "dev": true, "funding": [ { @@ -2950,19 +2926,6 @@ "node": ">= 10" } }, - "node_modules/compress-commons/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -3095,19 +3058,6 @@ "node": ">= 10" } }, - "node_modules/crc32-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -3163,9 +3113,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.11", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", - "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" }, "node_modules/debug": { "version": "2.6.9", @@ -3255,9 +3205,9 @@ "optional": true }, "node_modules/denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", "engines": { "node": ">=0.10" } @@ -3338,13 +3288,27 @@ "readable-stream": "^2.0.2" } }, - "node_modules/dynamic-dedupe": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", - "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", - "dev": true, - "dependencies": { - "xtend": "^4.0.0" + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/dynamic-dedupe": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", + "dev": true, + "dependencies": { + "xtend": "^4.0.0" } }, "node_modules/eastasianwidth": { @@ -3358,9 +3322,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.772", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.772.tgz", - "integrity": "sha512-jFfEbxR/abTTJA3ci+2ok1NTuOBBtB4jH+UT6PUmRN+DY3WSD4FFRsgoVQ+QNIJ0T7wrXwzsWCI2WKC46b++2A==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", + "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", "dev": true }, "node_modules/emittery": { @@ -3694,9 +3658,9 @@ } }, "node_modules/eslint/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -3762,9 +3726,9 @@ } }, "node_modules/eslint/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -3845,9 +3809,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -3934,19 +3898,6 @@ "node": ">=8.3.0" } }, - "node_modules/exceljs/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/exceljs/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -4105,6 +4056,11 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -4138,9 +4094,9 @@ "optional": true }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4192,6 +4148,22 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", @@ -4223,9 +4195,9 @@ } }, "node_modules/foreground-child": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz", - "integrity": "sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -4335,38 +4307,6 @@ "node": ">=0.6" } }, - "node_modules/fstream/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fstream/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -4462,21 +4402,20 @@ "optional": true }, "node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "*" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4494,28 +4433,6 @@ "node": ">= 6" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globals": { "version": "12.4.0", "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", @@ -4697,9 +4614,9 @@ } }, "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -4734,9 +4651,9 @@ } }, "node_modules/http-proxy-middleware/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -4755,9 +4672,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -4767,9 +4684,9 @@ } }, "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -4857,9 +4774,9 @@ } }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "dependencies": { "pkg-dir": "^4.2.0", @@ -4936,9 +4853,9 @@ } }, "node_modules/ioredis/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -4951,14 +4868,6 @@ } } }, - "node_modules/ioredis/node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/ioredis/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -5002,12 +4911,15 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", "dev": true, "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5108,9 +5020,9 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", - "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "dependencies": { "@babel/core": "^7.23.9", @@ -5124,9 +5036,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -5164,9 +5076,9 @@ } }, "node_modules/istanbul-lib-source-maps/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -5200,15 +5112,12 @@ } }, "node_modules/jackspeak": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", - "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -5385,27 +5294,6 @@ } } }, - "node_modules/jest-config/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/jest-config/node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -5713,27 +5601,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runtime/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/jest-snapshot": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", @@ -5766,9 +5633,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -6010,6 +5877,20 @@ "setimmediate": "^1.0.5" } }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/kafka-node": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz", @@ -6036,6 +5917,45 @@ "snappy": "^6.0.1" } }, + "node_modules/kafka-node/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/kafka-node/node_modules/bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/kafka-node/node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/kafka-node/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/kafka-node/node_modules/uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -6079,6 +5999,20 @@ "node": ">= 0.6.3" } }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -6213,9 +6147,9 @@ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" }, "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", + "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -6234,20 +6168,17 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/long": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/long/-/long-1.1.2.tgz", - "integrity": "sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", + "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==", "engines": { "node": ">=0.6" } }, "node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", - "engines": { - "node": "14 || >=16.14" - } + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "node_modules/make-dir": { "version": "4.0.0", @@ -6265,9 +6196,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -6349,11 +6280,11 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -6594,9 +6525,9 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/nan": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", - "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", "optional": true }, "node_modules/napi-build-utils": { @@ -6667,10 +6598,51 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/node-gyp/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -6684,9 +6656,9 @@ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, "node_modules/noop-logger": { @@ -6761,9 +6733,12 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6912,6 +6887,11 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -7419,6 +7399,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "engines": { "node": ">=6" } @@ -7497,17 +7478,16 @@ "dev": true }, "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/readdir-glob": { @@ -7667,40 +7647,15 @@ } }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, "node_modules/safe-buffer": { @@ -7722,9 +7677,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" }, "node_modules/saxes": { "version": "5.0.1", @@ -7992,22 +7947,22 @@ } }, "node_modules/socks-proxy-agent": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", - "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "engines": { "node": ">= 14" } }, "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -8408,6 +8363,16 @@ "tar-stream": "^1.1.2" } }, + "node_modules/tar-fs/node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "optional": true, + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, "node_modules/tar-fs/node_modules/pump": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", @@ -8418,7 +8383,22 @@ "once": "^1.3.1" } }, - "node_modules/tar-stream": { + "node_modules/tar-fs/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "optional": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/tar-fs/node_modules/tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", @@ -8436,14 +8416,19 @@ "node": ">= 0.8.0" } }, - "node_modules/tar-stream/node_modules/bl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "optional": true, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" } }, "node_modules/tar/node_modules/chownr": { @@ -8518,27 +8503,6 @@ "node": ">=8" } }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -8566,14 +8530,6 @@ "node": ">= 0.10.x" } }, - "node_modules/thriftrw/node_modules/long": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", - "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/tiny-case": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", @@ -8734,27 +8690,6 @@ } } }, - "node_modules/ts-node-dev/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ts-node-dev/node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -8767,23 +8702,10 @@ "node": ">=10" } }, - "node_modules/ts-node-dev/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/ts-node/node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -8887,9 +8809,9 @@ "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" }, "node_modules/unique-filename": { "version": "3.0.0", @@ -8938,10 +8860,24 @@ "setimmediate": "~1.0.4" } }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "dev": true, "funding": [ { @@ -8972,6 +8908,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -9014,9 +8951,9 @@ "dev": true }, "node_modules/v8-to-istanbul": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", - "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -9106,49 +9043,18 @@ } }, "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.1.tgz", + "integrity": "sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA==", "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", + "logform": "^2.6.1", + "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" }, "engines": { "node": ">= 12.0.0" } }, - "node_modules/winston-transport/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/winston/node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/winston/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/wmf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", @@ -9522,39 +9428,6 @@ "engines": { "node": ">= 10" } - }, - "node_modules/zip-stream/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/zip-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } } } } diff --git a/health-services/project-factory/package.json b/health-services/project-factory/package.json index 31dd40bc152..b6d62472b45 100644 --- a/health-services/project-factory/package.json +++ b/health-services/project-factory/package.json @@ -1,6 +1,6 @@ { "name": "project-factory", - "version": "0.2.0", + "version": "0.3.0", "main": "src/server/index.ts", "author": "Jagankumar ", "description": "Backend For Frontend service", @@ -26,7 +26,7 @@ "axios": "1.6.8", "body-parser": "^1.20.2", "compression": "1.7.4", - "exceljs": "4.4.0", + "exceljs": "^4.4.0", "express": "^4.19.2", "hash-sum": "2.0.0", "helmet": "7.1.0", diff --git a/health-services/project-factory/src/server/api/campaignApis.ts b/health-services/project-factory/src/server/api/campaignApis.ts index c063f1e653d..4f29fd481a8 100644 --- a/health-services/project-factory/src/server/api/campaignApis.ts +++ b/health-services/project-factory/src/server/api/campaignApis.ts @@ -1,21 +1,58 @@ import config from "../config"; -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4 } from "uuid"; import { httpRequest } from "../utils/request"; import { getFormattedStringForDebug, logger } from "../utils/logger"; -import createAndSearch from '../config/createAndSearch'; -import { getDataFromSheet, generateActivityMessage, throwError, translateSchema, replicateRequest, appendProjectTypeToCapacity } from "../utils/genericUtils"; -import { immediateValidationForTargetSheet, validateSheetData, validateTargetSheetData } from '../validators/campaignValidators'; +import createAndSearch from "../config/createAndSearch"; +import { + getDataFromSheet, + generateActivityMessage, + throwError, + translateSchema, + replicateRequest, + appendProjectTypeToCapacity, + getLocalizedMessagesHandler, +} from "../utils/genericUtils"; +import { + immediateValidationForTargetSheet, + validateEmptyActive, + validateSheetData, + validateTargetSheetData, + validateViaSchemaSheetWise, +} from "../validators/campaignValidators"; import { callMdmsTypeSchema, getCampaignNumber } from "./genericApis"; -import { boundaryBulkUpload, convertToTypeData, generateHierarchy, generateProcessedFileAndPersist, getBoundaryOnWhichWeSplit, getLocalizedName, reorderBoundariesOfDataAndValidate, checkIfSourceIsMicroplan } from "../utils/campaignUtils"; -const _ = require('lodash'); +import { + boundaryBulkUpload, + convertToTypeData, + generateHierarchy, + generateProcessedFileAndPersist, + getBoundaryOnWhichWeSplit, + getLocalizedName, + reorderBoundariesOfDataAndValidate, + checkIfSourceIsMicroplan, + createIdRequests, + createUniqueUserNameViaIdGen, + boundaryGeometryManagement, +} from "../utils/campaignUtils"; +const _ = require("lodash"); import { produceModifiedMessages } from "../kafka/Producer"; import { createDataService } from "../service/dataManageService"; import { searchProjectTypeCampaignService } from "../service/campaignManageService"; import { getExcelWorkbookFromFileURL } from "../utils/excelUtils"; -import { processTrackStatuses, processTrackTypes } from "../config/constants"; +import { + processTrackStatuses, + processTrackTypes, + resourceDataStatuses, +} from "../config/constants"; import { persistTrack } from "../utils/processTrackUtils"; - - +import { checkAndGiveIfParentCampaignAvailable } from "../utils/onGoingCampaignUpdateUtils"; +import { validateMicroplanFacility } from "../validators/microplanValidators"; +import { + createPlanFacilityForMicroplan, + updateFacilityDetailsForMicroplan, +} from "../utils/microplanUtils"; +import { getTransformedLocale } from "../utils/localisationUtils"; +import { BoundaryModels } from "../models"; +import { searchBoundaryRelationshipDefinition } from "./coreApis"; /** * Enriches the campaign data with unique IDs and generates campaign numbers. @@ -25,15 +62,30 @@ async function enrichCampaign(requestBody: any) { // Enrich campaign data with unique IDs and generate campaign numbers if (requestBody?.Campaign) { requestBody.Campaign.id = uuidv4(); - requestBody.Campaign.campaignNo = await getCampaignNumber(requestBody, config.values.idgen.format, config.values.idgen.idName, requestBody?.Campaign?.tenantId); + logger.info(`ENRICHMENT:: generated id for the campaign ${requestBody.Campaign.id}`); + requestBody.Campaign.campaignNo = await getCampaignNumber( + requestBody, + config.values.idgen.format, + config.values.idgen.idName, + requestBody?.Campaign?.tenantId + ); + logger.info(`ENRICHMENT:: generated sequence no for the campaign ${requestBody.Campaign.campaignNo}`); for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { campaignDetails.id = uuidv4(); } } } -async function getAllFacilitiesInLoop(searchedFacilities: any[], facilitySearchParams: any, facilitySearchBody: any) { - const response = await httpRequest(config.host.facilityHost + config.paths.facilitySearch, facilitySearchBody, facilitySearchParams); +async function getAllFacilitiesInLoop( + searchedFacilities: any[], + facilitySearchParams: any, + facilitySearchBody: any +) { + const response = await httpRequest( + config.host.facilityHost + config.paths.facilitySearch, + facilitySearchBody, + facilitySearchParams + ); if (Array.isArray(response?.Facilities)) { searchedFacilities.push(...response?.Facilities); @@ -54,20 +106,24 @@ async function getAllFacilities(tenantId: string, requestBody: any) { // Retrieve all facilities for the given tenant ID const facilitySearchBody = { RequestInfo: requestBody?.RequestInfo, - Facility: { isPermanent: true } + Facility: { isPermanent: true }, }; const facilitySearchParams = { limit: 50, offset: 0, - tenantId: tenantId?.split('.')?.[0] + tenantId: tenantId?.split(".")?.[0], }; const searchedFacilities: any[] = []; let searchAgain = true; while (searchAgain) { - searchAgain = await getAllFacilitiesInLoop(searchedFacilities, facilitySearchParams, facilitySearchBody); + searchAgain = await getAllFacilitiesInLoop( + searchedFacilities, + facilitySearchParams, + facilitySearchBody + ); facilitySearchParams.offset += 50; } @@ -81,17 +137,21 @@ async function getAllFacilities(tenantId: string, requestBody: any) { * @param requestBody The request body containing additional parameters. * @returns An array of facilities. */ -async function getFacilitiesViaIds(tenantId: string, ids: any[], requestBody: any) { +async function getFacilitiesViaIds( + tenantId: string, + ids: any[], + requestBody: any +) { // Retrieve facilities by their IDs const facilitySearchBody: any = { RequestInfo: requestBody?.RequestInfo, - Facility: {} + Facility: {}, }; const facilitySearchParams = { limit: 50, offset: 0, - tenantId: tenantId?.split('.')?.[0] + tenantId: tenantId?.split(".")?.[0], }; const searchedFacilities: any[] = []; @@ -100,7 +160,11 @@ async function getFacilitiesViaIds(tenantId: string, ids: any[], requestBody: an for (let i = 0; i < ids.length; i += 50) { const chunkIds = ids.slice(i, i + 50); facilitySearchBody.Facility.id = chunkIds; - await getAllFacilitiesInLoop(searchedFacilities, facilitySearchParams, facilitySearchBody); + await getAllFacilitiesInLoop( + searchedFacilities, + facilitySearchParams, + facilitySearchBody + ); } return searchedFacilities; @@ -122,13 +186,16 @@ function getParamsViaElements(elements: any, request: any) { if (element?.isInParams) { if (element?.value) { _.set(params, element?.keyPath, element?.value); - } - else if (element?.getValueViaPath) { - _.set(params, element?.keyPath, _.get(request.body, element?.getValueViaPath)) + } else if (element?.getValueViaPath) { + _.set( + params, + element?.keyPath, + _.get(request.body, element?.getValueViaPath) + ); } } } - return params + return params; } /** @@ -145,12 +212,14 @@ function changeBodyViaElements(elements: any, requestBody: any) { if (element?.isInBody) { if (element?.value) { _.set(requestBody, element?.keyPath, element?.value); - } - else if (element?.getValueViaPath) { - _.set(requestBody, element?.keyPath, _.get(requestBody, element?.getValueViaPath)) - } - else { - _.set(requestBody, element?.keyPath, {}) + } else if (element?.getValueViaPath) { + _.set( + requestBody, + element?.keyPath, + _.get(requestBody, element?.getValueViaPath) + ); + } else { + _.set(requestBody, element?.keyPath, {}); } } } @@ -171,132 +240,255 @@ function changeBodyViaElements(elements: any, requestBody: any) { // } // } -function updateErrorsForUser(newCreatedData: any[], newSearchedData: any[], errors: any[], createAndSearchConfig: any, userNameAndPassword: any[]) { +function updateErrorsForUser( + request: any, + newCreatedData: any[], + newSearchedData: any[], + errors: any[], + createAndSearchConfig: any, + userNameAndPassword: any[] +) { + const isSourceMicroplan = + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan"; newCreatedData.forEach((createdElement: any) => { let foundMatch = false; for (const searchedElement of newSearchedData) { if (searchedElement?.code === createdElement?.code) { foundMatch = true; newSearchedData.splice(newSearchedData.indexOf(searchedElement), 1); - errors.push({ status: "CREATED", rowNumber: createdElement["!row#number!"], isUniqueIdentifier: true, uniqueIdentifier: _.get(searchedElement, createAndSearchConfig.uniqueIdentifier, ""), errorDetails: "" }) + errors.push({ + status: "CREATED", + rowNumber: createdElement["!row#number!"], + isUniqueIdentifier: isSourceMicroplan ? false : true, + uniqueIdentifier: _.get( + searchedElement, + createAndSearchConfig.uniqueIdentifier, + "" + ), + errorDetails: "", + }); userNameAndPassword.push({ userName: searchedElement?.user?.userName, password: createdElement?.user?.password, - rowNumber: createdElement["!row#number!"] - }) + rowNumber: createdElement["!row#number!"], + }); break; } } if (!foundMatch) { - errors.push({ status: "NOT_CREATED", rowNumber: createdElement["!row#number!"], errorDetails: `Can't confirm creation of this data` }) - logger.info("Can't confirm creation of this data of row number : " + createdElement["!row#number!"]); + errors.push({ + status: "NOT_CREATED", + rowNumber: createdElement["!row#number!"], + errorDetails: `Can't confirm creation of this data`, + }); + logger.info( + "Can't confirm creation of this data of row number : " + + createdElement["!row#number!"] + ); } }); } -function updateErrors(newCreatedData: any[], newSearchedData: any[], errors: any[], createAndSearchConfig: any) { +function updateErrors( + newCreatedData: any[], + newSearchedData: any[], + errors: any[], + createAndSearchConfig: any +) { newCreatedData.forEach((createdElement: any) => { let foundMatch = false; for (const searchedElement of newSearchedData) { let match = true; for (const key in createdElement) { - if (createdElement[key] !== searchedElement[key] && key != '!row#number!') { + if ( + createdElement[key] !== searchedElement[key] && + key != "!row#number!" + ) { match = false; break; } } if (match) { foundMatch = true; + createdElement.id = searchedElement.id; newSearchedData.splice(newSearchedData.indexOf(searchedElement), 1); - errors.push({ status: "CREATED", rowNumber: createdElement["!row#number!"], isUniqueIdentifier: true, uniqueIdentifier: _.get(searchedElement, createAndSearchConfig.uniqueIdentifier, ""), errorDetails: "" }) + errors.push({ + status: "CREATED", + rowNumber: createdElement["!row#number!"], + isUniqueIdentifier: true, + uniqueIdentifier: _.get( + searchedElement, + createAndSearchConfig.uniqueIdentifier, + "" + ), + errorDetails: "", + }); break; } } if (!foundMatch) { - errors.push({ status: "NOT_CREATED", rowNumber: createdElement["!row#number!"], errorDetails: `Can't confirm creation of this data` }) - logger.info("Can't confirm creation of this data of row number : " + createdElement["!row#number!"]); + errors.push({ + status: "NOT_CREATED", + rowNumber: createdElement["!row#number!"], + errorDetails: `Can't confirm creation of this data`, + }); + logger.info( + "Can't confirm creation of this data of row number : " + + createdElement["!row#number!"] + ); } }); } - -function matchCreatedAndSearchedData(createdData: any[], searchedData: any[], request: any, createAndSearchConfig: any, activities: any) { +function matchCreatedAndSearchedData( + createdData: any[], + searchedData: any[], + request: any, + createAndSearchConfig: any, + activities: any +) { const newCreatedData = JSON.parse(JSON.stringify(createdData)); const newSearchedData = JSON.parse(JSON.stringify(searchedData)); const uid = createAndSearchConfig.uniqueIdentifier; newCreatedData.forEach((element: any) => { delete element[uid]; - }) - var errors: any[] = [] + }); + var errors: any[] = []; if (request?.body?.ResourceDetails?.type != "user") { if (request?.body?.ResourceDetails?.type == "facility") { newCreatedData?.forEach((element: any) => { - delete element.address - }) + delete element.address; + }); } - updateErrors(newCreatedData, newSearchedData, errors, createAndSearchConfig); - } - else { - var userNameAndPassword: any = [] - updateErrorsForUser(newCreatedData, newSearchedData, errors, createAndSearchConfig, userNameAndPassword); - request.body.userNameAndPassword = userNameAndPassword - } - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; - request.body.Activities = activities + updateErrors( + newCreatedData, + newSearchedData, + errors, + createAndSearchConfig + ); + updateFacilityDetailsForMicroplan(request, newCreatedData); + } else { + var userNameAndPassword: any = []; + updateErrorsForUser( + request, + newCreatedData, + newSearchedData, + errors, + createAndSearchConfig, + userNameAndPassword + ); + request.body.userNameAndPassword = userNameAndPassword; + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails + ? [...request?.body?.sheetErrorDetails, ...errors] + : errors; + request.body.Activities = activities; } -async function getUuidsError(request: any, response: any, mobileNumberRowNumberMapping: any) { - var errors: any[] = [] +async function getUuidsError( + request: any, + response: any, + mobileNumberRowNumberMapping: any +) { + var errors: any[] = []; var count = 0; - request.body.mobileNumberUuidsMapping = request.body.mobileNumberUuidsMapping ? request.body.mobileNumberUuidsMapping : {}; + request.body.mobileNumberUuidsMapping = request.body.mobileNumberUuidsMapping + ? request.body.mobileNumberUuidsMapping + : {}; for (const user of response.Individual) { if (!user?.userUuid) { - logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have userUuid`) - errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userUuid` }) + logger.info( + `User with mobileNumber ${user?.mobileNumber} doesn't have userUuid` + ); + errors.push({ + status: "INVALID", + rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], + errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userUuid`, + }); count++; - } - else if (!user?.userDetails?.username) { - logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have username`) - errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have username` }) + } else if (!user?.userDetails?.username) { + logger.info( + `User with mobileNumber ${user?.mobileNumber} doesn't have username` + ); + errors.push({ + status: "INVALID", + rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], + errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have username`, + }); count++; - } - else if (!user?.userDetails?.password) { - logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have password`) - errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have password` }) + } else if (!user?.userDetails?.password) { + logger.info( + `User with mobileNumber ${user?.mobileNumber} doesn't have password` + ); + errors.push({ + status: "INVALID", + rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], + errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have password`, + }); count++; - } - else if (!user?.userUuid) { - logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid`) - errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid` }) + } else if (!user?.userUuid) { + logger.info( + `User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid` + ); + errors.push({ + status: "INVALID", + rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], + errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid`, + }); count++; - } - else { - request.body.mobileNumberUuidsMapping[user?.mobileNumber] = { userUuid: user?.id, code: user?.userDetails?.username, rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], password: user?.userDetails?.password, userServiceUuid: user?.userUuid } + } else { + request.body.mobileNumberUuidsMapping[user?.mobileNumber] = { + userUuid: user?.id, + code: user?.userDetails?.username, + rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], + password: user?.userDetails?.password, + userServiceUuid: user?.userUuid, + }; } } if (count > 0) { - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails + ? [...request?.body?.sheetErrorDetails, ...errors] + : errors; } } -const createBatchRequest = async (request: any, batch: any[], mobileNumberRowNumberMapping: any) => { +const createBatchRequest = async ( + request: any, + batch: any[], + mobileNumberRowNumberMapping: any +) => { const searchBody = { RequestInfo: request?.body?.RequestInfo, Individual: { - mobileNumber: batch - } + mobileNumber: batch, + }, }; const params = { limit: 55, offset: 0, tenantId: request?.body?.ResourceDetails?.tenantId, - includeDeleted: true + includeDeleted: true, }; logger.info("Individual search to validate the mobile no initiated"); - const response = await httpRequest(config.host.healthIndividualHost + config.paths.healthIndividualSearch, searchBody, params, undefined, undefined, undefined, undefined, true); + const response = await httpRequest( + config.host.healthIndividualHost + config.paths.healthIndividualSearch, + searchBody, + params, + undefined, + undefined, + undefined, + undefined, + true + ); if (!response) { - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Error occurred during user search while validating mobile number."); + throwError( + "COMMON", + 400, + "INTERNAL_SERVER_ERROR", + "Error occurred during user search while validating mobile number." + ); } if (config.values.notCreateUserIfAlreadyThere) { await getUuidsError(request, response, mobileNumberRowNumberMapping); @@ -308,8 +500,14 @@ const createBatchRequest = async (request: any, batch: any[], mobileNumberRowNum return []; }; -async function getUserWithMobileNumbers(request: any, mobileNumbers: any[], mobileNumberRowNumberMapping: any) { - logger.info("mobileNumbers to search: " + JSON.stringify(mobileNumbers)); +async function getUserWithMobileNumbers( + request: any, + mobileNumbers: any[], + mobileNumberRowNumberMapping: any +) { + logger.debug( + "mobileNumbers to search: " + getFormattedStringForDebug(mobileNumbers) + ); const BATCH_SIZE = 50; let allResults: any[] = []; @@ -317,7 +515,9 @@ async function getUserWithMobileNumbers(request: any, mobileNumbers: any[], mobi const batchPromises = []; for (let i = 0; i < mobileNumbers.length; i += BATCH_SIZE) { const batch = mobileNumbers.slice(i, i + BATCH_SIZE); - batchPromises.push(createBatchRequest(request, batch, mobileNumberRowNumberMapping)); + batchPromises.push( + createBatchRequest(request, batch, mobileNumberRowNumberMapping) + ); } // Wait for all batch requests to complete @@ -333,87 +533,179 @@ async function getUserWithMobileNumbers(request: any, mobileNumbers: any[], mobi return resultSet; } - async function matchUserValidation(createdData: any[], request: any) { var count = 0; - const errors = [] - const mobileNumbers = createdData.filter(item => item?.user?.mobileNumber).map(item => (item?.user?.mobileNumber)); + const errors = []; + const mobileNumbers = createdData + .filter((item) => item?.user?.mobileNumber) + .map((item) => item?.user?.mobileNumber); const mobileNumberRowNumberMapping = createdData.reduce((acc, curr) => { acc[curr.user.mobileNumber] = curr["!row#number!"]; return acc; }, {}); - logger.info("mobileNumberRowNumberMapping : " + JSON.stringify(mobileNumberRowNumberMapping)); - const mobileNumberResponse = await getUserWithMobileNumbers(request, mobileNumbers, mobileNumberRowNumberMapping); + logger.debug( + "mobileNumberRowNumberMapping : " + + getFormattedStringForDebug(mobileNumberRowNumberMapping) + ); + const mobileNumberResponse = await getUserWithMobileNumbers( + request, + mobileNumbers, + mobileNumberRowNumberMapping + ); for (const key in mobileNumberRowNumberMapping) { - if (mobileNumberResponse.has(key) && !config.values.notCreateUserIfAlreadyThere) { - errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[key], errorDetails: `User with mobileNumber ${key} already exists` }) + if ( + mobileNumberResponse.has(key) && + !config.values.notCreateUserIfAlreadyThere + ) { + if (Array.isArray(mobileNumberRowNumberMapping[key])) { + for (const row of mobileNumberRowNumberMapping[key]) { + errors.push({ + status: "INVALID", + rowNumber: row.row, + sheetName: row.sheetName, + errorDetails: `User with contact number ${key} already exists`, + }); + } + } else { + errors.push({ + status: "INVALID", + rowNumber: mobileNumberRowNumberMapping[key], + errorDetails: `User with contact number ${key} already exists`, + }); + } count++; } } if (count) { - request.body.ResourceDetails.status = "invalid" + request.body.ResourceDetails.status = "invalid"; } logger.info("Invalid resources count : " + count); - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails + ? [...request?.body?.sheetErrorDetails, ...errors] + : errors; } -function matchViaUserIdAndCreationTime(createdData: any[], searchedData: any[], request: any, creationTime: any, createAndSearchConfig: any, activities: any) { +function matchViaUserIdAndCreationTime( + createdData: any[], + searchedData: any[], + request: any, + creationTime: any, + createAndSearchConfig: any, + activities: any +) { var matchingSearchData = []; - const userUuid = request?.body?.RequestInfo?.userInfo?.uuid + const userUuid = request?.body?.RequestInfo?.userInfo?.uuid; var count = 0; if (request?.body?.ResourceDetails?.type != "user") { for (const data of searchedData) { - if (data?.auditDetails?.createdBy == userUuid && data?.auditDetails?.createdTime >= creationTime) { + if ( + data?.auditDetails?.createdBy == userUuid && + data?.auditDetails?.createdTime >= creationTime + ) { matchingSearchData.push(data); count++; } } - } - else { + } else { count = searchedData.length; matchingSearchData = searchedData; } if (count < createdData.length) { - request.body.ResourceDetails.status = "PERSISTER_ERROR" - } - matchCreatedAndSearchedData(createdData, matchingSearchData, request, createAndSearchConfig, activities); + request.body.ResourceDetails.status = "PERSISTER_ERROR"; + } + matchCreatedAndSearchedData( + createdData, + matchingSearchData, + request, + createAndSearchConfig, + activities + ); logger.info("New created resources count : " + count); } -async function processSearch(createAndSearchConfig: any, request: any, params: any) { +async function processSearch( + createAndSearchConfig: any, + request: any, + params: any +) { setSearchLimits(createAndSearchConfig, request, params); - const arraysToMatch = await performSearch(createAndSearchConfig, request, params); + const arraysToMatch = await performSearch( + createAndSearchConfig, + request, + params + ); return arraysToMatch; } -function setSearchLimits(createAndSearchConfig: any, request: any, params: any) { - setLimitOrOffset(createAndSearchConfig?.searchDetails?.searchLimit, params, request.body); - setLimitOrOffset(createAndSearchConfig?.searchDetails?.searchOffset, params, request.body); +function setSearchLimits( + createAndSearchConfig: any, + request: any, + params: any +) { + setLimitOrOffset( + createAndSearchConfig?.searchDetails?.searchLimit, + params, + request.body + ); + setLimitOrOffset( + createAndSearchConfig?.searchDetails?.searchOffset, + params, + request.body + ); } -function setLimitOrOffset(limitOrOffsetConfig: any, params: any, requestBody: any) { +function setLimitOrOffset( + limitOrOffsetConfig: any, + params: any, + requestBody: any +) { if (limitOrOffsetConfig) { if (limitOrOffsetConfig?.isInParams) { - _.set(params, limitOrOffsetConfig?.keyPath, parseInt(limitOrOffsetConfig?.value)); + _.set( + params, + limitOrOffsetConfig?.keyPath, + parseInt(limitOrOffsetConfig?.value) + ); } if (limitOrOffsetConfig?.isInBody) { - _.set(requestBody, limitOrOffsetConfig?.keyPath, parseInt(limitOrOffsetConfig?.value)); + _.set( + requestBody, + limitOrOffsetConfig?.keyPath, + parseInt(limitOrOffsetConfig?.value) + ); } } } -async function performSearch(createAndSearchConfig: any, request: any, params: any) { +async function performSearch( + createAndSearchConfig: any, + request: any, + params: any +) { const arraysToMatch: any[] = []; let searchAgain = true; while (searchAgain) { const searcRequestBody = { - RequestInfo: request?.body?.RequestInfo - } - changeBodyViaElements(createAndSearchConfig?.searchDetails?.searchElements, searcRequestBody) - const response = await httpRequest(createAndSearchConfig?.searchDetails?.url, searcRequestBody, params); - const resultArray = _.get(response, createAndSearchConfig?.searchDetails?.searchPath); + RequestInfo: request?.body?.RequestInfo, + }; + changeBodyViaElements( + createAndSearchConfig?.searchDetails?.searchElements, + searcRequestBody + ); + const response = await httpRequest( + createAndSearchConfig?.searchDetails?.url, + searcRequestBody, + params + ); + const resultArray = _.get( + response, + createAndSearchConfig?.searchDetails?.searchPath + ); if (resultArray && Array.isArray(resultArray)) { arraysToMatch.push(...resultArray); - if (resultArray.length < parseInt(createAndSearchConfig?.searchDetails?.searchLimit?.value)) { + if ( + resultArray.length < + parseInt(createAndSearchConfig?.searchDetails?.searchLimit?.value) + ) { searchAgain = false; } } else { @@ -424,21 +716,32 @@ async function performSearch(createAndSearchConfig: any, request: any, params: a return arraysToMatch; } -function updateOffset(createAndSearchConfig: any, params: any, requestBody: any) { - const offsetConfig = createAndSearchConfig?.searchDetails?.searchOffset - const limit = createAndSearchConfig?.searchDetails?.searchLimit?.value +function updateOffset( + createAndSearchConfig: any, + params: any, + requestBody: any +) { + const offsetConfig = createAndSearchConfig?.searchDetails?.searchOffset; + const limit = createAndSearchConfig?.searchDetails?.searchLimit?.value; if (offsetConfig) { if (offsetConfig?.isInParams) { - _.set(params, offsetConfig?.keyPath, parseInt(_.get(params, offsetConfig?.keyPath) + parseInt(limit))); + _.set( + params, + offsetConfig?.keyPath, + parseInt(_.get(params, offsetConfig?.keyPath) + parseInt(limit)) + ); } if (offsetConfig?.isInBody) { - _.set(requestBody, offsetConfig?.keyPath, parseInt(_.get(requestBody, offsetConfig?.keyPath) + parseInt(limit))); + _.set( + requestBody, + offsetConfig?.keyPath, + parseInt(_.get(requestBody, offsetConfig?.keyPath) + parseInt(limit)) + ); } } } - -async function processSearchAndValidation(request: any, createAndSearchConfig: any, dataFromSheet: any[]) { +async function processSearchAndValidation(request: any) { // if (request?.body?.dataToSearch?.length > 0) { // const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request); // changeBodyViaElements(createAndSearchConfig?.searchDetails?.searchElements, request) @@ -447,36 +750,45 @@ async function processSearchAndValidation(request: any, createAndSearchConfig: a // matchData(request, request.body.dataToSearch, arraysToMatch, createAndSearchConfig) // } if (request?.body?.ResourceDetails?.type == "user") { - await enrichEmployees(request?.body?.dataToCreate, request) - await matchUserValidation(request.body.dataToCreate, request) + await enrichEmployees(request?.body?.dataToCreate, request); + await matchUserValidation(request.body.dataToCreate, request); } } async function getEmployeesBasedOnUuids(dataToCreate: any[], request: any) { const searchBody = { - RequestInfo: request?.body?.RequestInfo + RequestInfo: request?.body?.RequestInfo, }; const tenantId = request?.body?.ResourceDetails?.tenantId; const searchUrl = config.host.hrmsHost + config.paths.hrmsEmployeeSearch; logger.info(`Waiting for 10 seconds`); - await new Promise(resolve => setTimeout(resolve, 10000)); + await new Promise((resolve) => setTimeout(resolve, 10000)); const chunkSize = 50; let employeesSearched: any[] = []; for (let i = 0; i < dataToCreate.length; i += chunkSize) { const chunk = dataToCreate.slice(i, i + chunkSize); - const uuids = chunk.map((data: any) => data.uuid).join(','); + const uuids = chunk.map((data: any) => data.uuid).join(","); const params = { tenantId: tenantId, uuids: uuids, limit: 51, - offset: 0 + offset: 0, }; try { - const response = await httpRequest(searchUrl, searchBody, params, undefined, undefined, undefined, undefined, true); + const response = await httpRequest( + searchUrl, + searchBody, + params, + undefined, + undefined, + undefined, + undefined, + true + ); if (response && response.Employees) { employeesSearched = employeesSearched.concat(response.Employees); } else { @@ -484,105 +796,311 @@ async function getEmployeesBasedOnUuids(dataToCreate: any[], request: any) { } } catch (error: any) { console.log(error); - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", error.message || "Some internal error occurred while searching employees"); + throwError( + "COMMON", + 500, + "INTERNAL_SERVER_ERROR", + error.message || + "Some internal error occurred while searching employees" + ); } } return employeesSearched; } - - - - - // Confirms the creation of resources by matching created and searched data. -async function confirmCreation(createAndSearchConfig: any, request: any, dataToCreate: any[], creationTime: any, activities: any) { +async function confirmCreation( + createAndSearchConfig: any, + request: any, + dataToCreate: any[], + creationTime: any, + activities: any +) { // Confirm creation of resources by matching data // wait for 5 seconds if (request?.body?.ResourceDetails?.type != "user") { - const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request); - const arraysToMatch = await processSearch(createAndSearchConfig, request, params) - matchViaUserIdAndCreationTime(dataToCreate, arraysToMatch, request, creationTime, createAndSearchConfig, activities) - } - else { - const arraysToMatch = await getEmployeesBasedOnUuids(dataToCreate, request) - matchViaUserIdAndCreationTime(dataToCreate, arraysToMatch, request, creationTime, createAndSearchConfig, activities) + const params: any = getParamsViaElements( + createAndSearchConfig?.searchDetails?.searchElements, + request + ); + const arraysToMatch = await processSearch( + createAndSearchConfig, + request, + params + ); + matchViaUserIdAndCreationTime( + dataToCreate, + arraysToMatch, + request, + creationTime, + createAndSearchConfig, + activities + ); + } else { + const arraysToMatch = await getEmployeesBasedOnUuids(dataToCreate, request); + matchViaUserIdAndCreationTime( + dataToCreate, + arraysToMatch, + request, + creationTime, + createAndSearchConfig, + activities + ); } } -async function processValidateAfterSchema(dataFromSheet: any, request: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { +async function processValidateAfterSchema( + dataFromSheet: any, + request: any, + createAndSearchConfig: any, + localizationMap?: { [key: string]: string } +) { try { - const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) + validateEmptyActive(dataFromSheet, request?.body?.ResourceDetails?.type, localizationMap); + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == + "microplan" && + request?.body?.ResourceDetails?.type == "facility" + ) { + validateMicroplanFacility(request, dataFromSheet, localizationMap); + } + const typeData = await convertToTypeData( + request, + dataFromSheet, + createAndSearchConfig, + request.body, + localizationMap + ); request.body.dataToSearch = typeData.searchData; request.body.dataToCreate = typeData.createData; - await processSearchAndValidation(request, createAndSearchConfig, dataFromSheet) - await reorderBoundariesOfDataAndValidate(request, localizationMap) + await processSearchAndValidation(request); + await reorderBoundariesOfDataAndValidate(request, localizationMap); await generateProcessedFileAndPersist(request, localizationMap); } catch (error) { - console.log(error) + console.log(error); await handleResouceDetailsError(request, error); } } -async function processValidate(request: any, localizationMap?: { [key: string]: string }) { +export async function processValidateAfterSchemaSheetWise( + request: any, + createAndSearchConfig: any, + localizationMap?: { [key: string]: string } +) { + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" && + request.body.ResourceDetails.type == "user" + ) { + await generateProcessedFileAndPersist(request, localizationMap); + } +} + +async function processSheetWise( + forCreate: any, + dataFromSheet: any, + request: any, + createAndSearchConfig: any, + translatedSchema: any, + localizationMap?: { [key: string]: string } +) { + try { + const errorMap: any = await validateViaSchemaSheetWise( + dataFromSheet, + translatedSchema, + request, + localizationMap + ); + enrichErrorIfSheetInvalid(request, errorMap); + await processSearchAndValidation(request); + if (request?.body?.sheetErrorDetails?.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid; + await generateProcessedFileAndPersist(request, localizationMap); + } else { + if (forCreate) { + await processAfterValidation( + dataFromSheet, + createAndSearchConfig, + request, + localizationMap + ); + } else { + await processValidateAfterSchemaSheetWise( + request, + createAndSearchConfig, + localizationMap + ); + } + } + } catch (error) { + console.log(error); + await handleResouceDetailsError(request, error); + } +} + +function enrichErrorIfSheetInvalid(request: any, errorMap: any) { + if (Object.keys(errorMap).length > 0) { + var sheetErrorDetails = []; + for (const sheetName of Object.keys(errorMap)) { + const errorData = errorMap[sheetName]; + for (const row of Object.keys(errorData)) { + if (errorData[row].length > 0) { + const errorDetails = errorData[row].join(", "); + sheetErrorDetails.push({ + status: "INVALID", + sheetName: sheetName, + rowNumber: row, + errorDetails: errorDetails, + }); + } + } + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails + ? [...request?.body?.sheetErrorDetails, ...sheetErrorDetails] + : sheetErrorDetails; + } +} + +async function processValidate( + request: any, + localizationMap?: { [key: string]: string } +) { const type: string = request.body.ResourceDetails.type; const tenantId = request.body.ResourceDetails.tenantId; - const createAndSearchConfig = createAndSearch[type] - const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, null, localizationMap) - if (type == 'boundaryWithTarget') { - let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request); - differentTabsBasedOnLevel = getLocalizedName(`${request?.body?.ResourceDetails?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), localizationMap); + const createAndSearchConfig = createAndSearch[type]; + const dataFromSheet: any = await getDataFromSheet( + request, + request?.body?.ResourceDetails?.fileStoreId, + request?.body?.ResourceDetails?.tenantId, + createAndSearchConfig, + null, + localizationMap + ); + if (type == "boundaryWithTarget") { + const hierarchyType = request?.body?.ResourceDetails?.hierarchyType; + const hierarchyModule = `${config.localisation.boundaryPrefix + }-${getTransformedLocale(hierarchyType)}`?.toLowerCase(); + const localizationMapForHierarchy = await getLocalizedMessagesHandler( + request, + request?.body?.ResourceDetails?.tenantId, + hierarchyModule + ); + localizationMap = { + ...localizationMap, + ...localizationMapForHierarchy, + }; + let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request, request?.body?.ResourceDetails?.tenantId); + differentTabsBasedOnLevel = getLocalizedName( + `${request?.body?.ResourceDetails?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), + localizationMap + ); logger.info("target sheet format validation started"); - await immediateValidationForTargetSheet(request, dataFromSheet, differentTabsBasedOnLevel, localizationMap); - logger.info("target sheet format validation completed and starts with data validation"); - validateTargetSheetData(dataFromSheet, request, createAndSearchConfig?.boundaryValidation, differentTabsBasedOnLevel, localizationMap); - } - - else { + await immediateValidationForTargetSheet( + request, + dataFromSheet, + differentTabsBasedOnLevel, + localizationMap + ); + logger.info( + "target sheet format validation completed and starts with data validation" + ); + validateTargetSheetData( + dataFromSheet, + request, + createAndSearchConfig?.boundaryValidation, + differentTabsBasedOnLevel, + localizationMap + ); + } else { let schema: any; if (type == "facility" || type == "user") { - const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); - schema = mdmsResponse + const isUpdate = request?.body?.parentCampaignObject ? true : false; + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ) { + schema = await callMdmsTypeSchema( + request, + tenantId, + isUpdate, + type, + "microplan" + ); + } else { + schema = await callMdmsTypeSchema(request, tenantId, isUpdate, type); + } } const translatedSchema = await translateSchema(schema, localizationMap); - await validateSheetData(dataFromSheet, request, translatedSchema, createAndSearchConfig?.boundaryValidation, localizationMap) - processValidateAfterSchema(dataFromSheet, request, createAndSearchConfig, localizationMap) + if (Array.isArray(dataFromSheet)) { + if ( + request?.body?.ResourceDetails?.additionalDetails?.source != "microplan" + ) { + await validateSheetData( + dataFromSheet, + request, + translatedSchema, + createAndSearchConfig?.boundaryValidation, + localizationMap + ); + } + processValidateAfterSchema( + dataFromSheet, + request, + createAndSearchConfig, + localizationMap + ); + } else { + if (dataFromSheet && Object.keys(dataFromSheet).length > 0) { + processSheetWise( + false, + dataFromSheet, + request, + createAndSearchConfig, + translatedSchema, + localizationMap + ); + } else { + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + "No data filled in the sheet." + ); + } + } } } function convertUserRoles(employees: any[], request: any) { for (const employee of employees) { if (employee?.user?.roles) { - var newRoles: any[] = [] - const rolesArray = employee.user.roles.split(',').map((role: any) => role.trim()); - for (const role of rolesArray) { - const code = role.toUpperCase().split(' ').join('_') - newRoles.push({ name: role, code: code, tenantId: request?.body?.ResourceDetails?.tenantId }) + var newRoles: any[] = []; + if (!Array.isArray(employee.user.roles)) { + const rolesArray = employee.user.roles + .split(",") + .map((role: any) => role.trim()); + for (const role of rolesArray) { + const code = role.toUpperCase().split(" ").join("_"); + newRoles.push({ + name: role, + code: code, + tenantId: request?.body?.ResourceDetails?.tenantId, + }); + } + employee.user.roles = newRoles; } - employee.user.roles = newRoles } } } -function generateHash(input: string): string { - const prime = 31; // Prime number - let hash = 0; - for (let i = 0; i < input.length; i++) { - hash = (hash * prime + input.charCodeAt(i)) % 100000; // Limit hash to 5 digits - } - return hash.toString().padStart(6, '0'); -} - function generateUserPassword() { // Function to generate a random lowercase letter function getRandomLowercaseLetter() { - const letters = 'abcdefghijklmnopqrstuvwxyz'; + const letters = "abcdefghijklmnopqrstuvwxyz"; return letters.charAt(Math.floor(Math.random() * letters.length)); } // Function to generate a random uppercase letter function getRandomUppercaseLetter() { - const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; return letters.charAt(Math.floor(Math.random() * letters.length)); } @@ -607,20 +1125,6 @@ function generateUserPassword() { return `${firstSequence}@${randomNumber}`; } - -function enrichUserNameAndPassword(employees: any[]) { - const epochTime = Date.now(); - employees.forEach((employee) => { - const { user, "!row#number!": rowNumber } = employee; - const nameInitials = user.name.split(' ').map((name: any) => name.charAt(0)).join(''); - const generatedCode = `${nameInitials}${generateHash(`${epochTime}`)}${rowNumber}`; - const generatedPassword = config?.user?.userPasswordAutoGenerate == "true" ? generateUserPassword() : config?.user?.userDefaultPassword - user.userName = generatedCode; - user.password = generatedPassword; - employee.code = generatedCode - }); -} - async function enrichJurisdictions(employee: any, request: any) { employee.jurisdictions = [ { @@ -628,92 +1132,199 @@ async function enrichJurisdictions(employee: any, request: any) { boundaryType: config.values.userMainBoundaryType, boundary: config.values.userMainBoundary, hierarchy: request?.body?.ResourceDetails?.hierarchyType, - roles: employee?.user?.roles - } - ] + roles: employee?.user?.roles, + }, + ]; } async function enrichEmployees(employees: any[], request: any) { - convertUserRoles(employees, request) + convertUserRoles(employees, request); + const idRequests = createIdRequests(employees); + request.body.idRequests = idRequests; + let result = await createUniqueUserNameViaIdGen(request); + var i = 0; for (const employee of employees) { - enrichUserNameAndPassword(employees) - await enrichJurisdictions(employee, request) + const { user } = employee; + const generatedPassword = + config?.user?.userPasswordAutoGenerate == "true" + ? generateUserPassword() + : config?.user?.userDefaultPassword; + user.userName = result?.idResponses?.[i]?.id; + user.password = generatedPassword; + employee.code = result?.idResponses?.[i]?.id; + await enrichJurisdictions(employee, request); if (employee?.user) { - employee.user.tenantId = request?.body?.ResourceDetails?.tenantId - employee.user.dob = 0 + employee.user.tenantId = request?.body?.ResourceDetails?.tenantId; + employee.user.dob = 0; } + i++; } } -function enrichDataToCreateForUser(dataToCreate: any[], responsePayload: any, request: any) { +function enrichDataToCreateForUser( + dataToCreate: any[], + responsePayload: any, + request: any +) { const createdEmployees = responsePayload?.Employees; - // create an object which have keys as employee.code and values as employee.uuid + // create an object which have keys as employee.code and values as employee.uuid const employeeMap = createdEmployees.reduce((map: any, employee: any) => { - map[employee.code] = employee.uuid; + map[employee.code] = { + uuid: employee?.uuid, + userServiceUuid: employee?.user?.userServiceUuid, + }; return map; }, {}); for (const employee of dataToCreate) { - if (!employee?.uuid && employeeMap[employee?.code]) { - employee.uuid = employeeMap[employee?.code]; + const mappedEmployee = employeeMap[employee?.code]; + if (mappedEmployee) { + if (!employee?.userServiceUuid) { + employee.userServiceUuid = mappedEmployee.userServiceUuid; + } + if (!employee?.uuid) { + employee.uuid = mappedEmployee.uuid; + } } } } -async function handeFacilityProcess(request: any, createAndSearchConfig: any, params: any, activities: any[], newRequestBody: any) { +async function handeFacilityProcess( + request: any, + createAndSearchConfig: any, + params: any, + activities: any[], + newRequestBody: any +) { for (const facility of newRequestBody.Facilities) { - facility.address = {} - } - var responsePayload = await httpRequest(createAndSearchConfig?.createBulkDetails?.url, newRequestBody, params, "post", undefined, undefined, true); - var activity = await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, responsePayload, "facility", createAndSearchConfig?.createBulkDetails?.url, responsePayload?.statusCode) - logger.info(`Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}`); + facility.address = {}; + } + var responsePayload = await httpRequest( + createAndSearchConfig?.createBulkDetails?.url, + newRequestBody, + params, + "post", + undefined, + undefined, + true + ); + var activity = await generateActivityMessage( + request?.body?.ResourceDetails?.tenantId, + request.body, + newRequestBody, + responsePayload, + "facility", + createAndSearchConfig?.createBulkDetails?.url, + responsePayload?.statusCode + ); + logger.info( + `Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}` + ); activities.push(activity); } - -async function handleUserProcess(request: any, createAndSearchConfig: any, params: any, dataToCreate: any[], activities: any[], newRequestBody: any) { +async function handleUserProcess( + request: any, + createAndSearchConfig: any, + params: any, + dataToCreate: any[], + activities: any[], + newRequestBody: any +) { if (config.values.notCreateUserIfAlreadyThere) { - var Employees: any[] = [] + var Employees: any[] = []; if (request.body?.mobileNumberUuidsMapping) { for (const employee of newRequestBody.Employees) { - if (request.body.mobileNumberUuidsMapping[employee?.user?.mobileNumber]) { - logger.info(`User with mobile number ${employee?.user?.mobileNumber} already exist`); - } - else { - Employees.push(employee) + if ( + request.body.mobileNumberUuidsMapping[employee?.user?.mobileNumber] + ) { + logger.info( + `User with mobile number ${employee?.user?.mobileNumber} already exist` + ); + } else { + Employees.push(employee); } } } - newRequestBody.Employees = Employees + newRequestBody.Employees = Employees; } if (newRequestBody.Employees.length > 0) { - var responsePayload = await httpRequest(createAndSearchConfig?.createBulkDetails?.url, newRequestBody, params, "post", undefined, undefined, true, true); + var responsePayload = await httpRequest( + createAndSearchConfig?.createBulkDetails?.url, + newRequestBody, + params, + "post", + undefined, + undefined, + true, + false + ); if (responsePayload?.Employees && responsePayload?.Employees?.length > 0) { enrichDataToCreateForUser(dataToCreate, responsePayload, request); + } else { + throwError( + "COMMON", + 500, + "INTERNAL_SERVER_ERROR", + "Some internal server error occured during user creation." + ); } - else { - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Some internal server error occured during user creation."); - } - var activity = await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, responsePayload, "user", createAndSearchConfig?.createBulkDetails?.url, responsePayload?.statusCode) - logger.info(`Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}`); + var activity = await generateActivityMessage( + request?.body?.ResourceDetails?.tenantId, + request.body, + newRequestBody, + responsePayload, + "user", + createAndSearchConfig?.createBulkDetails?.url, + responsePayload?.statusCode + ); + logger.info( + `Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}` + ); activities.push(activity); } } async function enrichAlreadyExsistingUser(request: any) { - if (request.body.ResourceDetails.type == "user" && request?.body?.mobileNumberUuidsMapping) { + if ( + request.body.ResourceDetails.type == "user" && + request?.body?.mobileNumberUuidsMapping + ) { for (const employee of request.body.dataToCreate) { - if (request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber]) { - employee.uuid = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].userUuid; - employee.code = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].code; - employee.user.userName = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].code; - employee.user.password = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].password; - employee.user.userServiceUuid = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].userServiceUuid; + if ( + request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber] + ) { + employee.uuid = + request?.body?.mobileNumberUuidsMapping[ + employee?.user?.mobileNumber + ].userUuid; + employee.code = + request?.body?.mobileNumberUuidsMapping[ + employee?.user?.mobileNumber + ].code; + employee.user.userName = + request?.body?.mobileNumberUuidsMapping[ + employee?.user?.mobileNumber + ].code; + employee.user.password = + request?.body?.mobileNumberUuidsMapping[ + employee?.user?.mobileNumber + ].password; + employee.user.userServiceUuid = + request?.body?.mobileNumberUuidsMapping[ + employee?.user?.mobileNumber + ].userServiceUuid; } } } } -async function performAndSaveResourceActivity(request: any, createAndSearchConfig: any, params: any, type: any, localizationMap?: { [key: string]: string }) { +async function performAndSaveResourceActivity( + request: any, + createAndSearchConfig: any, + params: any, + type: any, + localizationMap?: { [key: string]: string } +) { logger.info(type + " create data "); if (createAndSearchConfig?.createBulkDetails?.limit) { const limit = createAndSearchConfig?.createBulkDetails?.limit; @@ -727,20 +1338,46 @@ async function performAndSaveResourceActivity(request: any, createAndSearchConfi const chunkData = dataToCreate.slice(start, end); // Get a chunk of data const newRequestBody: any = { RequestInfo: request?.body?.RequestInfo, - } - _.set(newRequestBody, createAndSearchConfig?.createBulkDetails?.createPath, chunkData); + }; + _.set( + newRequestBody, + createAndSearchConfig?.createBulkDetails?.createPath, + chunkData + ); creationTime = Date.now(); if (type == "facility" || type == "facilityMicroplan") { - await handeFacilityProcess(request, createAndSearchConfig, params, activities, newRequestBody); - } - else if (type == "user") { - await handleUserProcess(request, createAndSearchConfig, params, chunkData, activities, newRequestBody); + await handeFacilityProcess( + request, + createAndSearchConfig, + params, + activities, + newRequestBody + ); + } else if (type == "user") { + await handleUserProcess( + request, + createAndSearchConfig, + params, + chunkData, + activities, + newRequestBody + ); } + // wait for 5 seconds after each chunk + logger.info(`Waiting for 5 seconds after each chunk`); + await new Promise((resolve) => setTimeout(resolve, 5000)); } await enrichAlreadyExsistingUser(request); - logger.info(`Waiting for 10 seconds`); - await new Promise(resolve => setTimeout(resolve, 10000)); - await confirmCreation(createAndSearchConfig, request, dataToCreate, creationTime, activities); + logger.info(`Final waiting for 10 seconds`); + await new Promise((resolve) => setTimeout(resolve, 10000)); + await confirmCreation( + createAndSearchConfig, + request, + dataToCreate, + creationTime, + activities + ); + await createPlanFacilityForMicroplan(request, localizationMap); } await generateProcessedFileAndPersist(request, localizationMap); } @@ -749,13 +1386,33 @@ async function performAndSaveResourceActivity(request: any, createAndSearchConfi * Processes generic requests such as create or validate. * @param request The HTTP request object. */ -async function processGenericRequest(request: any, localizationMap?: { [key: string]: string }) { +async function processGenericRequest( + request: any, + localizationMap?: { [key: string]: string } +) { // Process generic requests - if (request?.body?.ResourceDetails?.action == "create") { - await processCreate(request, localizationMap) + if ( + request?.body?.ResourceDetails?.type != "boundary" && + request?.body?.ResourceDetails?.type != "boundaryManagement" + ) { + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + if ( + campaignObject?.additionalDetails?.resourceDistributionStrategy == + "HOUSE_TO_HOUSE" + ) { + request.body.showFixedPost = false; + } else { + request.body.showFixedPost = true; + } + request.body.projectTypeCode = campaignObject?.projectType; + await checkAndGiveIfParentCampaignAvailable(request, campaignObject); } - else { - await processValidate(request, localizationMap) + + if (request?.body?.ResourceDetails?.action == "create") { + await processCreate(request, localizationMap); + } else { + await processValidate(request, localizationMap); } } @@ -763,73 +1420,139 @@ async function handleResouceDetailsError(request: any, error: any) { var stringifiedError: any; if (error?.description || error?.message) { stringifiedError = JSON.stringify({ - status: error.status || '', - code: error.code || '', - description: error.description || '', - message: error.message || '' + status: error.status || "", + code: error.code || "", + description: error.description || "", + message: error.message || "", }); - } - else { - if (typeof error == "object") - stringifiedError = JSON.stringify(error); + } else { + if (typeof error == "object") stringifiedError = JSON.stringify(error); else { - stringifiedError = error + stringifiedError = error; } } - logger.error("Error while processing after validation : " + error) + logger.error("Error while processing after validation : " + error); if (request?.body?.ResourceDetails) { request.body.ResourceDetails.status = "failed"; request.body.ResourceDetails.additionalDetails = { ...request?.body?.ResourceDetails?.additionalDetails, - error: stringifiedError + error: stringifiedError, + }; + const persistMessage: any = { + ResourceDetails: request.body.ResourceDetails, }; - const persistMessage: any = { ResourceDetails: request.body.ResourceDetails } if (request?.body?.ResourceDetails?.action == "create") { - persistMessage.ResourceDetails.additionalDetails = { error: stringifiedError } + persistMessage.ResourceDetails.additionalDetails = { + error: stringifiedError, + }; } - await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); - } - if (request?.body?.Activities && Array.isArray(request?.body?.Activities) && request?.body?.Activities.length > 0) { + await produceModifiedMessages( + persistMessage, + config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC + ); + } + if ( + request?.body?.Activities && + Array.isArray(request?.body?.Activities) && + request?.body?.Activities.length > 0 + ) { logger.info("Waiting for 2 seconds"); - await new Promise(resolve => setTimeout(resolve, 2000)); - const activityObject = request?.body?.Activities; - await produceModifiedMessages(activityObject, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + await new Promise((resolve) => setTimeout(resolve, 2000)); + + const activities = request?.body?.Activities; + const chunkPromises = []; + for (let i = 0; i < activities.length; i += 10) { + const chunk = activities.slice(i, Math.min(i + 10, activities.length)); + const activityObject: any = { Activities: chunk }; + chunkPromises.push( + produceModifiedMessages( + activityObject, + config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC + ) + ); + } + await Promise.all(chunkPromises); } } async function persistCreationProcess(request: any, status: any) { if (request?.body?.ResourceDetails?.type == "facility") { - await persistTrack(request?.body?.ResourceDetails?.campaignId, processTrackTypes.facilityCreation, status); - } - else if (request?.body?.ResourceDetails?.type == "user") { - await persistTrack(request?.body?.ResourceDetails?.campaignId, processTrackTypes.staffCreation, status); + await persistTrack( + request?.body?.ResourceDetails?.campaignId, + processTrackTypes.facilityCreation, + status + ); + } else if (request?.body?.ResourceDetails?.type == "user") { + await persistTrack( + request?.body?.ResourceDetails?.campaignId, + processTrackTypes.staffCreation, + status + ); } } -async function processAfterValidation(dataFromSheet: any, createAndSearchConfig: any, request: any, localizationMap?: { [key: string]: string }) { - await persistCreationProcess(request, processTrackStatuses.inprogress) +async function processAfterValidation( + dataFromSheet: any, + createAndSearchConfig: any, + request: any, + localizationMap?: { [key: string]: string } +) { + await persistCreationProcess(request, processTrackStatuses.inprogress); try { - const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) - request.body.dataToCreate = typeData.createData; - request.body.dataToSearch = typeData.searchData; - await processSearchAndValidation(request, createAndSearchConfig, dataFromSheet) - await reorderBoundariesOfDataAndValidate(request, localizationMap) - if (createAndSearchConfig?.createBulkDetails && request.body.ResourceDetails.status != "invalid") { - _.set(request.body, createAndSearchConfig?.createBulkDetails?.createPath, request?.body?.dataToCreate); - const params: any = getParamsViaElements(createAndSearchConfig?.createBulkDetails?.createElements, request); - changeBodyViaElements(createAndSearchConfig?.createBulkDetails?.createElements, request) - await performAndSaveResourceActivity(request, createAndSearchConfig, params, request.body.ResourceDetails.type, localizationMap); + validateEmptyActive(dataFromSheet, request?.body?.ResourceDetails?.type, localizationMap); + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == + "microplan" && + request.body.ResourceDetails.type == "user" + ) { + await processSearchAndValidation(request); + } else { + const typeData = await convertToTypeData( + request, + dataFromSheet, + createAndSearchConfig, + request.body, + localizationMap + ); + request.body.dataToCreate = typeData.createData; + request.body.dataToSearch = typeData.searchData; + await processSearchAndValidation(request); + await reorderBoundariesOfDataAndValidate(request, localizationMap); } - else if (request.body.ResourceDetails.status == "invalid") { + if ( + createAndSearchConfig?.createBulkDetails && + request.body.ResourceDetails.status != "invalid" + ) { + _.set( + request.body, + createAndSearchConfig?.createBulkDetails?.createPath, + request?.body?.dataToCreate + ); + const params: any = getParamsViaElements( + createAndSearchConfig?.createBulkDetails?.createElements, + request + ); + changeBodyViaElements( + createAndSearchConfig?.createBulkDetails?.createElements, + request + ); + await performAndSaveResourceActivity( + request, + createAndSearchConfig, + params, + request.body.ResourceDetails.type, + localizationMap + ); + } else if (request.body.ResourceDetails.status == "invalid") { await generateProcessedFileAndPersist(request, localizationMap); } } catch (error: any) { - console.log(error) - await persistCreationProcess(request, processTrackStatuses.failed) - await handleResouceDetailsError(request, error) + console.log(error); + await persistCreationProcess(request, processTrackStatuses.failed); + await handleResouceDetailsError(request, error); } - await persistCreationProcess(request, processTrackStatuses.completed) + await persistCreationProcess(request, processTrackStatuses.completed); } /** @@ -840,53 +1563,151 @@ async function processCreate(request: any, localizationMap?: any) { // Process creation of resources const type: string = request.body.ResourceDetails.type; const tenantId = request?.body?.ResourceDetails?.tenantId; - if (type == "boundary") { + if (type == "boundary" || type == "boundaryManagement") { boundaryBulkUpload(request, localizationMap); - } - else { + } else if (type == "boundaryGeometryManagement") { + await boundaryGeometryManagement(request, localizationMap); + } else { // console.log(`Source is MICROPLAN -->`, source); let createAndSearchConfig: any; createAndSearchConfig = createAndSearch[type]; const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; + const campaignType = + responseFromCampaignSearch?.CampaignDetails[0]?.projectType; if (checkIfSourceIsMicroplan(request?.body?.ResourceDetails)) { logger.info(`Data create Source is MICROPLAN`); if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { - createAndSearchConfig.parseArrayConfig.parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic.map( - (item: any) => { + createAndSearchConfig.parseArrayConfig.parseLogic = + createAndSearchConfig.parseArrayConfig.parseLogic.map((item: any) => { if (item.sheetColumn === "E") { item.sheetColumnName += `_${campaignType}`; } return item; - } - ); + }); } } - const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, undefined, localizationMap) - let schema: any; + const dataFromSheet = await getDataFromSheet( + request, + request?.body?.ResourceDetails?.fileStoreId, + request?.body?.ResourceDetails?.tenantId, + createAndSearchConfig, + undefined, + localizationMap + ); + const schema = await getSchema(request, tenantId, type, campaignType); + await processAfterGettingSchema( + dataFromSheet, + schema, + request, + createAndSearchConfig, + localizationMap + ); + } +} - if (type == "facility") { - logger.info("Fetching schema to validate the created data for type: " + type); - const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); - schema = mdmsResponse - } - else if (type == "facilityMicroplan") { - const mdmsResponse = await callMdmsTypeSchema(request, tenantId, "facility", "microplan"); - schema = mdmsResponse - logger.info("Appending project type to capacity for microplan " + campaignType); - schema = await appendProjectTypeToCapacity(schema, campaignType); +async function getSchema( + request: any, + tenantId: string, + type: string, + campaignType: string +) { + let schema: any; + const isUpdate = request?.body?.parentCampaignObject ? true : false; + if (type == "facility") { + logger.info( + "Fetching schema to validate the created data for type: " + type + ); + const mdmsResponse = await callMdmsTypeSchema( + request, + tenantId, + isUpdate, + type + ); + schema = mdmsResponse; + } else if (type == "facilityMicroplan") { + const mdmsResponse = await callMdmsTypeSchema( + request, + tenantId, + isUpdate, + "facility", + "microplan" + ); + schema = mdmsResponse; + logger.info( + "Appending project type to capacity for microplan " + campaignType + ); + schema = await appendProjectTypeToCapacity(schema, campaignType); + } else if (type == "user") { + logger.info( + "Fetching schema to validate the created data for type: " + type + ); + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ) { + const mdmsResponse = await callMdmsTypeSchema( + request, + tenantId, + isUpdate, + type, + "microplan" + ); + schema = mdmsResponse; + } else { + const mdmsResponse = await callMdmsTypeSchema( + request, + tenantId, + isUpdate, + type + ); + schema = mdmsResponse; } - else if (type == "user") { - logger.info("Fetching schema to validate the created data for type: " + type); - const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); - schema = mdmsResponse + } + return schema; +} + +async function processAfterGettingSchema( + dataFromSheet: any, + schema: any, + request: any, + createAndSearchConfig: any, + localizationMap?: any +) { + logger.info("translating schema"); + const translatedSchema = await translateSchema(schema, localizationMap); + if (Array.isArray(dataFromSheet)) { + await validateSheetData( + dataFromSheet, + request, + translatedSchema, + createAndSearchConfig?.boundaryValidation, + localizationMap + ); + logger.info("validation done sucessfully"); + processAfterValidation( + dataFromSheet, + createAndSearchConfig, + request, + localizationMap + ); + } else { + if (dataFromSheet && Object.keys(dataFromSheet).length > 0) { + processSheetWise( + true, + dataFromSheet, + request, + createAndSearchConfig, + translatedSchema, + localizationMap + ); + } else { + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + "No data filled in the sheet." + ); } - logger.info("translating schema") - const translatedSchema = await translateSchema(schema, localizationMap); - await validateSheetData(dataFromSheet, request, translatedSchema, createAndSearchConfig?.boundaryValidation, localizationMap); - logger.info("validation done sucessfully") - processAfterValidation(dataFromSheet, createAndSearchConfig, request, localizationMap) } } @@ -895,41 +1716,65 @@ async function processCreate(request: any, localizationMap?: any) { * @param request The HTTP request object. */ async function createProjectCampaignResourcData(request: any) { - await persistTrack(request.body.CampaignDetails.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.inprogress); + await persistTrack( + request.body.CampaignDetails.id, + processTrackTypes.triggerResourceCreation, + processTrackStatuses.inprogress + ); try { // Create resources for a project campaign - if (request?.body?.CampaignDetails?.action == "create" && request?.body?.CampaignDetails?.resources) { + if ( + request?.body?.CampaignDetails?.action == "create" && + request?.body?.CampaignDetails?.resources + ) { for (const resource of request?.body?.CampaignDetails?.resources) { - if (resource.type != "boundaryWithTarget") { - const resourceDetails = { - type: resource.type, - fileStoreId: resource.filestoreId, - tenantId: request?.body?.CampaignDetails?.tenantId, - action: "create", - hierarchyType: request?.body?.CampaignDetails?.hierarchyType, - additionalDetails: {}, - campaignId: request?.body?.CampaignDetails?.id - }; - logger.info(`Creating the resources for type ${resource.type}`) - logger.debug("resourceDetails " + getFormattedStringForDebug(resourceDetails)) - const createRequestBody = { - RequestInfo: request.body.RequestInfo, - ResourceDetails: resourceDetails - } - const req = replicateRequest(request, createRequestBody) - const res: any = await createDataService(req) - if (res?.id) { - resource.createResourceId = res?.id - } + const action = + resource?.type === "boundaryWithTarget" ? "validate" : "create"; + // if (resource.type != "boundaryWithTarget") { + const resourceDetails = { + type: resource.type, + fileStoreId: resource.filestoreId, + tenantId: request?.body?.CampaignDetails?.tenantId, + action: action, + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + additionalDetails: {}, + campaignId: request?.body?.CampaignDetails?.id, + }; + logger.info(`Creating the resources for type ${resource.type}`); + logger.debug( + "resourceDetails " + getFormattedStringForDebug(resourceDetails) + ); + const createRequestBody = { + RequestInfo: request.body.RequestInfo, + ResourceDetails: resourceDetails, + }; + const req = replicateRequest(request, createRequestBody); + const res: any = await createDataService(req); + if (res?.id) { + resource.createResourceId = res?.id; } } } } catch (error: any) { - console.log(error) - await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); - throw new Error(error) - } - await persistTrack(request.body.CampaignDetails.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.completed); + console.log(error); + await persistTrack( + request?.body?.CampaignDetails?.id, + processTrackTypes.triggerResourceCreation, + processTrackStatuses.failed, + { + error: String( + error?.message + + (error?.description ? ` : ${error?.description}` : "") || error + ), + } + ); + throw new Error(error); + } + await persistTrack( + request.body.CampaignDetails.id, + processTrackTypes.triggerResourceCreation, + processTrackStatuses.completed + ); } async function confirmProjectParentCreation(request: any, projectId: any) { @@ -938,46 +1783,121 @@ async function confirmProjectParentCreation(request: any, projectId: any) { Projects: [ { id: projectId, - tenantId: request.body.CampaignDetails.tenantId - } - ] - } + tenantId: request.body.CampaignDetails.tenantId, + }, + ], + }; const params = { tenantId: request.body.CampaignDetails.tenantId, offset: 0, - limit: 5 - } + limit: 5, + }; var projectFound = false; var retry = 6; while (!projectFound && retry >= 0) { - const response = await httpRequest(config.host.projectHost + config.paths.projectSearch, searchBody, params); + const response = await httpRequest( + config.host.projectHost + config.paths.projectSearch, + searchBody, + params + ); if (response?.Project?.[0]) { projectFound = true; - } - else { + } else { logger.info("Project not found. Waiting for 1 seconds"); - retry = retry - 1 + retry = retry - 1; logger.info(`Waiting for ${retry} for 1 more second`); - await new Promise(resolve => setTimeout(resolve, 1000)); + await new Promise((resolve) => setTimeout(resolve, 1000)); } } if (!projectFound) { - throwError("PROJECT", 500, "PROJECT_CONFIRMATION_FAILED", "Project confirmation failed, for the project with id " + projectId); + throwError( + "PROJECT", + 500, + "PROJECT_CONFIRMATION_FAILED", + "Project confirmation failed, for the project with id " + projectId + ); } } async function projectCreate(projectCreateBody: any, request: any) { - logger.info("Project creation API started") - logger.debug("Project creation body " + getFormattedStringForDebug(projectCreateBody)) - const projectCreateResponse = await httpRequest(config.host.projectHost + config.paths.projectCreate, projectCreateBody, undefined, undefined, undefined, undefined, undefined, true); - logger.debug("Project creation response" + getFormattedStringForDebug(projectCreateResponse)) + logger.info("Project creation API started"); + logger.debug( + "Project creation body " + getFormattedStringForDebug(projectCreateBody) + ); + if (!request.body.newlyCreatedBoundaryProjectMap) { + request.body.newlyCreatedBoundaryProjectMap = {}; + } + const projectCreateResponse = await httpRequest( + config.host.projectHost + config.paths.projectCreate, + projectCreateBody, + undefined, + undefined, + undefined, + undefined, + undefined, + true + ); + logger.debug( + "Project creation response" + + getFormattedStringForDebug(projectCreateResponse) + ); if (projectCreateResponse?.Project[0]?.id) { - logger.info("Project created successfully with name " + JSON.stringify(projectCreateResponse?.Project[0]?.name)) - logger.info(`for boundary type ${projectCreateResponse?.Project[0]?.address?.boundaryType} and code ${projectCreateResponse?.Project[0]?.address?.boundary}`) - request.body.boundaryProjectMapping[projectCreateBody?.Projects?.[0]?.address?.boundary].projectId = projectCreateResponse?.Project[0]?.id + logger.info( + "Project created successfully with name " + + JSON.stringify(projectCreateResponse?.Project[0]?.name) + ); + logger.info( + `for boundary type ${projectCreateResponse?.Project[0]?.address?.boundaryType} and code ${projectCreateResponse?.Project[0]?.address?.boundary}` + ); + // if ( + // !request.body.newlyCreatedBoundaryProjectMap[ + // projectCreateBody?.Projects?.[0]?.address?.boundary + // ] + // ) { + // request.body.newlyCreatedBoundaryProjectMap[ + // projectCreateBody?.Projects?.[0]?.address?.boundary + // ] = {}; + // } + request.body.boundaryProjectMapping[ + projectCreateBody?.Projects?.[0]?.address?.boundary + ].projectId = projectCreateResponse?.Project[0]?.id; + // request.body.newlyCreatedBoundaryProjectMap[ + // projectCreateBody?.Projects?.[0]?.address?.boundary + // ].projectId = projectCreateResponse?.Project[0]?.id; + } else { + throwError( + "PROJECT", + 500, + "PROJECT_CREATION_FAILED", + "Project creation failed, for the request: " + + JSON.stringify(projectCreateBody) + ); } - else { - throwError("PROJECT", 500, "PROJECT_CREATION_FAILED", "Project creation failed, for the request: " + JSON.stringify(projectCreateBody)); +} + +async function projectUpdateForTargets(projectUpdateBody: any, request: any, boundaryCode: any) { + logger.info("Project Update For Targets started"); + + logger.debug("Project update request body: " + getFormattedStringForDebug(projectUpdateBody)); + logger.info(`Project update started for boundary code: ${boundaryCode} and project name: ${request?.body?.CampaignDetails?.campaignName}`); + + try { + const projectUpdateResponse = await httpRequest( + config.host.projectHost + config.paths.projectUpdate, + projectUpdateBody, + undefined, undefined, undefined, undefined, undefined, + true + ); + logger.debug("Project update response: " + getFormattedStringForDebug(projectUpdateResponse)); + logger.info(`Project update response for boundary code: ${boundaryCode} and project name: ${request?.body?.CampaignDetails?.campaignName}`); + } catch (error: any) { + logger.error("Project update failed", error); + throwError( + "PROJECT", + 500, + "PROJECT_UPDATE_ERROR", + `Project update failed for the request: ${getFormattedStringForDebug(projectUpdateBody)}. Error: ${getFormattedStringForDebug(error.message)}` + ); } } @@ -989,7 +1909,7 @@ function generateHierarchyList(data: any[], parentChain: any = []) { let currentChain = [...parentChain, boundary.code]; // Add the current chain to the result - result.push(currentChain.join(',')); + result.push(currentChain.join(",")); // If there are children, recursively call the function if (boundary.children && boundary.children.length > 0) { @@ -998,52 +1918,69 @@ function generateHierarchyList(data: any[], parentChain: any = []) { } } return result; - } -const getHierarchy = async (request: any, tenantId: string, hierarchyType: string) => { - const url = `${config.host.boundaryHost}${config.paths.boundaryHierarchy}`; - - // Create request body - const requestBody = { - "RequestInfo": request?.body?.RequestInfo, - "BoundaryTypeHierarchySearchCriteria": { - "tenantId": tenantId, - "limit": 5, - "offset": 0, - "hierarchyType": hierarchyType - } +const getHierarchy = async ( + request: any, + tenantId: string, + hierarchyType: string +) => { + const BoundaryTypeHierarchySearchCriteria: BoundaryModels.BoundaryHierarchyDefinitionSearchCriteria = + { + BoundaryTypeHierarchySearchCriteria: { + tenantId, + hierarchyType, + }, }; - - const response = await httpRequest(url, requestBody); + const response: BoundaryModels.BoundaryHierarchyDefinitionResponse = + await searchBoundaryRelationshipDefinition( + BoundaryTypeHierarchySearchCriteria + ); const boundaryList = response?.BoundaryHierarchy?.[0].boundaryHierarchy; return generateHierarchy(boundaryList); }; -const getHeadersOfBoundarySheet = async (fileUrl: string, sheetName: string, getRow = false, localizationMap?: any) => { - const localizedBoundarySheetName = getLocalizedName(sheetName, localizationMap); - const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, localizedBoundarySheetName); +const getHeadersOfBoundarySheet = async ( + fileUrl: string, + sheetName: string, + getRow = false, + localizationMap?: any +) => { + const localizedBoundarySheetName = getLocalizedName( + sheetName, + localizationMap + ); + const workbook: any = await getExcelWorkbookFromFileURL( + fileUrl, + localizedBoundarySheetName + ); const worksheet = workbook.getWorksheet(localizedBoundarySheetName); - const columnsToValidate = worksheet.getRow(1).values.map((header: any) => header ? header.toString().trim() : undefined); + const columnsToValidate = worksheet + .getRow(1) + .values.map((header: any) => + header ? header.toString().trim() : undefined + ); // Filter out empty items and return the result - return columnsToValidate.filter((header: any) => typeof header === 'string'); -} - + return columnsToValidate.filter((header: any) => typeof header === "string"); +}; async function getCampaignSearchResponse(request: any) { try { logger.info(`searching for campaign details`); - const requestInfo = { "RequestInfo": request?.body?.RequestInfo }; - const campaignDetails = { "CampaignDetails": { tenantId: request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, "ids": [request?.query?.campaignId || request?.body?.ResourceDetails?.campaignId] } } - const requestBody = { ...requestInfo, ...campaignDetails }; - const req: any = replicateRequest(request, requestBody) - const projectTypeSearchResponse: any = await searchProjectTypeCampaignService(req); +const CampaignDetails = { + tenantId: request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, + ids: [request?.query?.campaignId || request?.body?.ResourceDetails?.campaignId], +}; + const projectTypeSearchResponse: any = + await searchProjectTypeCampaignService(CampaignDetails); return projectTypeSearchResponse; } catch (error: any) { - logger.error(`Error while searching for campaign details: ${error.message}`); - throwError("COMMON", 400, "RESPONSE_NOT_FOUND_ERROR", error?.message) + logger.error( + `Error while searching for campaign details: ${error.message}` + ); + throwError("COMMON", 400, "RESPONSE_NOT_FOUND_ERROR", error?.message); } } @@ -1063,5 +2000,6 @@ export { getHeadersOfBoundarySheet, handleResouceDetailsError, getCampaignSearchResponse, - confirmProjectParentCreation + confirmProjectParentCreation, + projectUpdateForTargets }; diff --git a/health-services/project-factory/src/server/api/coreApis.ts b/health-services/project-factory/src/server/api/coreApis.ts new file mode 100644 index 00000000000..aa9ba13003c --- /dev/null +++ b/health-services/project-factory/src/server/api/coreApis.ts @@ -0,0 +1,259 @@ +// Import necessary types and utilities +import { BoundaryModels, MDMSModels } from "../models"; +import config from "../config"; +import { httpRequest } from "../utils/request"; + +// Default request information for MDMS API requests +export const defaultRequestInfo: any = { + RequestInfo: { + apiId: "PROJECTFACTORY", // Identifier for the calling application, + msgId: `${new Date().getTime()}|${config.localisation.defaultLocale}`, + ...(config.isProduction && config.token && { authToken :config.token}), + ...{ userInfo:{ + tenantId:config?.app?.defaultTenantId + }}, + }, +}; + +/** + * Searches MDMS data via the v2 API for specific unique identifiers. + * + * @author jagankumar-egov + * + * @param MdmsCriteria - The criteria for the MDMS v2 search, including tenantId and schemaCode. + * @returns Promise resolving to the MDMS v2 search response containing matched data. + */ +const searchMDMSDataViaV2Api = async ( + MdmsCriteria: MDMSModels.MDMSv2RequestCriteria +): Promise => { + // Construct the full API URL for the v2 MDMS search + const apiUrl: string = config.host.mdmsV2 + config.paths.mdms_v2_search; + + // Prepare the data payload for the API request + const data = { + MdmsCriteria, + ...defaultRequestInfo, + }; + + // Make an HTTP request to the MDMS v2 API + const response: MDMSModels.MDMSv2Response = await httpRequest(apiUrl, data); + + // Return the response from the API + return response; +}; + +/** + * Fetches the schema definitions from MDMS based on specified criteria. + * + * @author jagankumar-egov + * + * @param SchemaDefCriteria - The criteria for fetching schema definitions, including tenantId and limit. + * @returns Promise resolving to the response containing schema definitions. + */ +const searchMDMSSchema = async ( + SchemaDefCriteria: MDMSModels.MDMSSchemaRequestCriteria +): Promise => { + // Construct the request body including schema criteria and default request info + const requestBody = { + ...SchemaDefCriteria, + ...defaultRequestInfo, + }; + + // Define the API URL for schema retrieval + const url = config.host.mdmsV2 + config.paths.mdmsSchema; + + // Make an HTTP request with a tenant ID in headers + const response: MDMSModels.MDMSSchemaResponse = await httpRequest( + url, + requestBody, + { tenantId: SchemaDefCriteria?.SchemaDefCriteria?.tenantId } + ); + + // Return the schema definitions from the response + return response; +}; + +/** + * Searches MDMS data via the v1 API using given criteria. + * + * @author jagankumar-egov + * + * @param MdmsCriteria - The criteria for the MDMS v1 search, including tenantId and moduleDetails. + * @returns Promise resolving to the MDMS v1 search response. + */ +const searchMDMSDataViaV1Api = async ( + MdmsCriteria: MDMSModels.MDMSv1RequestCriteria +): Promise => { + // Construct the request body with v1 search criteria and default request info + const requestBody = { + ...MdmsCriteria, + ...defaultRequestInfo, + }; + + // Define the API URL for MDMS v1 search + const url = config.host.mdmsV2 + config.paths.mdms_v1_search; + + // Make an HTTP request with tenant ID in headers + const response: MDMSModels.MDMSv1Response = await httpRequest( + url, + requestBody, + { tenantId: MdmsCriteria.MdmsCriteria.tenantId } + ); + + // Return the search result from MDMS v1 + return response; +}; + + +/** + * Searches boundary entities in the MDMS system using specified criteria. + * + * @author jagankumar-egov + * + * @function searchBoundaryEntity + * @param tenantId - Unique identifier for the tenant. + * @param codes - Specific codes to filter the boundary entities. + * @param limit - Maximum number of results to return (default is 100). + * @param offset - Starting position for fetching results (default is 0). + * @returns Promise resolving to the boundary entity search response. + * + * @remarks + * This function constructs and sends a request to the boundary entity service, + * using the provided criteria to filter and retrieve specific boundary entities. + * Additional headers contain tenant ID, offset, limit, and codes for filtering. + * + * @example + * const response = await searchBoundaryEntity("mz", "MOZ", 50, 0); + */ +const searchBoundaryEntity = async ( + tenantId: string, + codes: string, + limit: number = 100, + offset: number = 0, +): Promise => { + // Prepare request body with default request information + const requestBody = { + ...defaultRequestInfo, + }; + + // Construct API URL for boundary entity search + const url = config.host.boundaryHost + config.paths.boundaryServiceSearch; + + // Execute HTTP request with tenant ID, offset, limit, and codes in headers + const response: BoundaryModels.BoundaryEntityResponse = await httpRequest( + url, + requestBody, + { tenantId, offset, limit, codes } + ); + + // Return the response containing boundary entity data + return response; +}; + +/** + * Searches boundary hierarchy relationship data within the MDMS system. + * + * @author jagankumar-egov + * + * @function searchBoundaryRelationshipData + * @param tenantId - Unique identifier for the tenant. + * @param hierarchyType - Type of hierarchy to search within. + * @param includeChildren - Whether to include child relationships (default is true). + * @param includeParents - Whether to include parent relationships (default is true). + * @returns Promise resolving to the boundary hierarchy relationship response. + * + * @remarks + * This function queries the boundary relationship API to retrieve hierarchy data + * based on the specified hierarchy type and inclusion of child or parent entities. + * + * @example + * const response = await searchBoundaryRelationshipData("mz", "ADMIN", true, false); + */ +const searchBoundaryRelationshipData = async ( + tenantId: string, + hierarchyType: string, + includeChildren: boolean = true, + includeParents: boolean = true, +): Promise => { + // Prepare request body with default request information + const requestBody = { + ...defaultRequestInfo, + }; + + // Construct API URL for boundary hierarchy relationship search + const url = config.host.boundaryHost + config.paths.boundaryRelationship; + + // Execute HTTP request with tenant ID, hierarchy type, and inclusion flags in headers + const response: BoundaryModels.BoundaryHierarchyRelationshipResponse = await httpRequest( + url, + requestBody, + { tenantId, hierarchyType, includeChildren, includeParents } + ); + + // Return the response containing boundary relationship data + return response; +}; + +/** + * Searches boundary hierarchy definitions based on provided search criteria. + * + * @author jagankumar-egov + * + * @function searchBoundaryRelationshipDefinition + * @param BoundaryTypeHierarchySearchCriteria - Criteria for fetching boundary hierarchy definitions. + * @returns Promise resolving to the boundary hierarchy definition response. + * + * @remarks + * This function sends a request to retrieve hierarchy definitions for boundary types, + * based on specified criteria such as tenant ID and hierarchy parameters. + * + * @example + * const criteria = { tenantId: "mz", hierarchyCode: "ADMIN" }; + * const response = await searchBoundaryRelationshipDefinition(criteria); + */ +const searchBoundaryRelationshipDefinition = async ( + BoundaryTypeHierarchySearchCriteria: BoundaryModels.BoundaryHierarchyDefinitionSearchCriteria +): Promise => { + // Prepare request body with search criteria and default request information + const requestBody = { + ...BoundaryTypeHierarchySearchCriteria, + ...defaultRequestInfo, + }; + + // Construct API URL for boundary hierarchy definition search + const url = config.host.boundaryHost + config.paths.boundaryHierarchy; + + // Execute HTTP request to fetch boundary hierarchy definitions + const response: BoundaryModels.BoundaryHierarchyDefinitionResponse = await httpRequest( + url, + requestBody, + ); + + // Return the response containing hierarchy definition data + return response; +}; + + + +const fetchFileFromFilestore=async(filestoreId:string,tenantId:string)=> { + + try { + const reqParamsForFetchingFile = { + tenantId: tenantId, + fileStoreIds: filestoreId + }; + const fileResponse= await httpRequest( + `${config?.host?.filestore}${config?.paths?.filestorefetch}`, + {}, + reqParamsForFetchingFile, + "get" + ); + return fileResponse?.fileStoreIds?.[0].url; + } catch (error) { + console.error("Error fetching file URLs:", error); + throw error; + } +} + +// Exporting all API functions for MDMS operations +export { searchMDMSDataViaV2Api, searchMDMSSchema, searchMDMSDataViaV1Api ,searchBoundaryEntity, searchBoundaryRelationshipData, searchBoundaryRelationshipDefinition ,fetchFileFromFilestore}; diff --git a/health-services/project-factory/src/server/api/genericApis.ts b/health-services/project-factory/src/server/api/genericApis.ts index c7fa9ced8e0..2ae5f0f7491 100644 --- a/health-services/project-factory/src/server/api/genericApis.ts +++ b/health-services/project-factory/src/server/api/genericApis.ts @@ -60,36 +60,36 @@ function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheet return jsonData; } -function validateFirstRowColumn(createAndSearchConfig: any, worksheet: any, localizationMap: any) { - if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { - const parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic; - // Iterate over each column configuration - for (const columnConfig of parseLogic) { - const { sheetColumn, sheetColumnName } = columnConfig; - const localizedColumnName = getLocalizedName(sheetColumnName, localizationMap); - - // Get the value of the first row in the current column - if (sheetColumn && localizedColumnName) { - const firstRowValue = worksheet.getCell(sheetColumn + '1').value; - - // Validate the first row of the current column - if (firstRowValue !== localizedColumnName) { - throwError( - "FILE", - 400, - "INVALID_COLUMNS", - `Invalid format: Expected '${localizedColumnName}' in the first row of column ${sheetColumn}.` - ); - } - } - } - } -} +// function validateFirstRowColumn(createAndSearchConfig: any, worksheet: any, localizationMap: any) { +// if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { +// const parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic; +// // Iterate over each column configuration +// for (const columnConfig of parseLogic) { +// const { sheetColumn, sheetColumnName } = columnConfig; +// const localizedColumnName = getLocalizedName(sheetColumnName, localizationMap); + +// // Get the value of the first row in the current column +// if (sheetColumn && localizedColumnName) { +// const firstRowValue = worksheet.getCell(sheetColumn + '1').value; + +// // Validate the first row of the current column +// if (firstRowValue !== localizedColumnName) { +// throwError( +// "FILE", +// 400, +// "INVALID_COLUMNS", +// `Invalid format: Expected '${localizedColumnName}' in the first row of column ${sheetColumn}.` +// ); +// } +// } +// } +// } +// } function getSheetDataFromWorksheet(worksheet: any) { var sheetData: any[][] = []; - worksheet.eachRow({ includeEmpty: true }, (row: any, rowNumber: any) => { + worksheet?.eachRow({ includeEmpty: true }, (row: any, rowNumber: any) => { const rowData: any[] = []; row.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { @@ -120,7 +120,7 @@ const getSheetData = async ( const worksheet: any = workbook.getWorksheet(localizedSheetName); // If parsing array configuration is provided, validate first row of each column - validateFirstRowColumn(createAndSearchConfig, worksheet, localizationMap); + // validateFirstRowColumn(createAndSearchConfig, worksheet, localizationMap); // Collect sheet data by iterating through rows and cells const sheetData = getSheetDataFromWorksheet(worksheet); @@ -134,16 +134,31 @@ function getRawCellValue(cell: any) { if ('richText' in cell.value) { // Handle rich text return cell.value.richText.map((rt: any) => rt.text).join(''); - } else if ('formula' in cell.value) { + } + else if ('hyperlink' in cell.value) { + if (cell?.value?.text?.richText?.length > 0) { + return cell.value.text.richText.map((t: any) => t.text).join(''); + } + else { + return cell.value.text; + } + } + else if ('formula' in cell.value) { // Get the result of the formula return cell.value.result; - } else if ('error' in cell.value) { + } + else if ('sharedFormula' in cell.value) { + // Get the result of the shared formula + return cell.value.result; + } + else if ('error' in cell.value) { // Get the error value return cell.value.error; } else if (cell.value instanceof Date) { // Handle date values return cell.value.toISOString(); - } else { + } + else { // Return as-is for other object types return cell.value; } @@ -175,6 +190,7 @@ const getTargetSheetData = async ( }; const getTargetSheetDataAfterCode = async ( + request: any, fileUrl: string, getRow = false, getSheetName = false, @@ -196,36 +212,54 @@ const getTargetSheetDataAfterCode = async ( // Find the target column index where the first row value matches codeColumnName const firstRow = sheetData[0]; - let targetColumnIndex = -1; + let boundaryCodeColumnIndex = -1; for (let colIndex = 1; colIndex < firstRow.length; colIndex++) { if (firstRow[colIndex] === codeColumnName) { - targetColumnIndex = colIndex; + boundaryCodeColumnIndex = colIndex; break; } } - if (targetColumnIndex === -1) { + if (boundaryCodeColumnIndex === -1) { console.warn(`Column "${codeColumnName}" not found in sheet "${sheetName}".`); continue; } // Process data from sheet const processedData = sheetData.map((row: any, rowIndex: any) => { - if (rowIndex <= 1) return null; // Skip header row + if (rowIndex <= 0) return null; // Skip header row - let rowData: any = { [codeColumnName]: row[targetColumnIndex] }; + let rowData: any = { [codeColumnName]: row[boundaryCodeColumnIndex] }; // Add integer values in the target column for the current row - let sum = 0; - for (let colIndex = targetColumnIndex + 1; colIndex < row.length; colIndex++) { + let sumOfCurrentTargets = 0; + let sumOfParentTargets = 0; + const remainingColumns = row.length - boundaryCodeColumnIndex - 1; + const halfPoint = Math.floor(remainingColumns / 2); + let startColIndex = boundaryCodeColumnIndex + 1; + + if (request?.body?.parentCampaign) { + for (let colIndex = startColIndex; colIndex < startColIndex + halfPoint; colIndex++) { + const value = row[colIndex]; + if (typeof value === 'number' && Number.isInteger(value)) { + sumOfParentTargets += value; + } + } + // Add the sum to the row data + rowData['Parent Target at the Selected Boundary level'] = sumOfParentTargets; + + // Calculate middle point of remaining columns + startColIndex = boundaryCodeColumnIndex + 1 + halfPoint; + } + for (let colIndex = startColIndex; colIndex < row.length; colIndex++) { const value = row[colIndex]; if (typeof value === 'number' && Number.isInteger(value)) { - sum += value; + sumOfCurrentTargets += value; } } // Add the sum to the row data - rowData['Target at the Selected Boundary level'] = sum; + rowData['Target at the Selected Boundary level'] = sumOfCurrentTargets; return rowData; }).filter(Boolean); // Remove null entries @@ -248,7 +282,7 @@ const searchMDMS: any = async ( } // Construct API URL for MDMS search - const apiUrl = config.host.mdms + config.paths.mdms_search; + const apiUrl = config.host.mdmsV2 + config.paths.mdms_v2_search; // Construct request data for MDMS search const data = { @@ -375,7 +409,7 @@ const getSchema: any = async (code: string, RequestInfo: any) => { codes: [code], }, }; - const mdmsSearchUrl = config.host.mdms + config.paths.mdmsSchema; + const mdmsSearchUrl = config.host.mdmsV2 + config.paths.mdmsSchema; try { const result = await httpRequest( @@ -434,12 +468,62 @@ async function createAndUploadFile( request: any, tenantId?: any ) { - // Write the updated workbook to a buffer - const buffer = await updatedWorkbook.xlsx.writeBuffer(); + let retries: any = 3; + while (retries--) { + try { + // Write the updated workbook to a buffer + const buffer = await updatedWorkbook.xlsx.writeBuffer(); + + // Create form data for file upload + const formData = new FormData(); + formData.append("file", buffer, "filename.xlsx"); + formData.append( + "tenantId", + tenantId ? tenantId : request?.body?.RequestInfo?.userInfo?.tenantId + ); + formData.append("module", "HCM-ADMIN-CONSOLE-SERVER"); + + // Make HTTP request to upload file + var fileCreationResult = await httpRequest( + config.host.filestore + config.paths.filestore, + formData, + undefined, + undefined, + undefined, + { + "Content-Type": "multipart/form-data", + "auth-token": request?.body?.RequestInfo?.authToken || request?.RequestInfo?.authToken, + } + ); + + // Extract response data + const responseData = fileCreationResult?.files; + if (responseData) { + return responseData; + } + } + catch (error: any) { + console.error(`Attempt failed:`, error.message); + + // Add a delay before the next retry (2 seconds) + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + } + throw new Error("Error while uploading excel file: INTERNAL_SERVER_ERROR"); +} + +async function createAndUploadJsonFile( + jsonData: any, // Expecting JSON data as an argument + request: any, + tenantId?: any +) { + // Convert JSON data to a string + const jsonString = JSON.stringify(jsonData); + const buffer = Buffer.from(jsonString); // Create form data for file upload const formData = new FormData(); - formData.append("file", buffer, "filename.xlsx"); + formData.append("file", buffer, { filename: "filename.json", contentType: "application/json" }); formData.append( "tenantId", tenantId ? tenantId : request?.body?.RequestInfo?.userInfo?.tenantId @@ -463,13 +547,14 @@ async function createAndUploadFile( const responseData = fileCreationResult?.files; if (!responseData) { throw new Error( - "Error while uploading excel file: INTERNAL_SERVER_ERROR" + "Error while uploading JSON file: INTERNAL_SERVER_ERROR" ); } return responseData; // Return the response data } + // Function to generate a list of hierarchy codes function generateHierarchyList(data: any[], parentChain: any = []) { let result: any[] = []; @@ -581,7 +666,7 @@ async function getAutoGeneratedBoundaryCodes(boundaryList: any, childParentMap: for (let i = 0; i < columnsData.length; i++) { const column = columnsData[i]; for (const element of column) { - if (!findMapValue(elementCodesMap, element)) { + if (!findMapValue(elementCodesMap, element) && element.value !== '') { const parentElement = findMapValue(childParentMap, element); if (parentElement !== undefined && parentElement !== null) { const parentBoundaryCode = findMapValue(elementCodesMap, parentElement); @@ -610,9 +695,36 @@ async function getAutoGeneratedBoundaryCodes(boundaryList: any, childParentMap: } } } + modifyElementCodesMap(elementCodesMap); // Modify the element codes map return elementCodesMap; // Return the updated element codes map } +function modifyElementCodesMap(elementCodesMap: any) { + const set = new Set(); + const specialCharsRegex = /[^\w]/g; // Regular expression to match any character that is not a word character + + // Iterate over each [key, value] pair in elementCodesMap using forEach + elementCodesMap.forEach((value: any, key: any) => { + let modifiedValue = value.replace(specialCharsRegex, '_').trim(); // Replace special characters and spaces with underscore + let modifiedTempValue = modifiedValue; // Store the initial modified value + let count = 1; + + // Generate a unique modified value + while (set.has(modifiedValue)) { + // If it exists, append _ to modifiedValue + modifiedValue = `${modifiedTempValue}_${count}`; + count++; + } + + // Add the modified (or original) value to the set + set.add(modifiedValue); + + // Update the map with the modified value + elementCodesMap.set(key, modifiedValue); + }); + +} + /** * Function to generate an element code based on sequence, parent code, and element. * @param sequence Sequence number @@ -678,7 +790,14 @@ async function getBoundarySheetData( modifiedHierarchy, localizationMap ); - const headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); + var headerColumnsAfterHierarchy; + if (request?.query?.type != "boundaryManagement" && request?.query?.type !== 'boundaryGeometryManagement') { + headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); + } + + if (request?.query?.type === "boundaryManagement" || request?.query?.type === 'boundaryGeometryManagement') { + headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement(request, localizationMap); + } const headers = [...localizedHeadersUptoHierarchy, ...headerColumnsAfterHierarchy]; // create empty sheet if no boundary present in system // const localizedBoundaryTab = getLocalizedName( @@ -702,11 +821,11 @@ async function getBoundarySheetData( } }; } - else { + else if (request?.query?.type !== "boundaryManagement") { // logger.info("boundaryData for sheet " + JSON.stringify(boundaryData)) const responseFromCampaignSearch = await getCampaignSearchResponse(request); - Filters = getFiltersFromCampaignSearchResponse(responseFromCampaignSearch) + Filters = await getFiltersFromCampaignSearchResponse(request, responseFromCampaignSearch) } if (Filters?.Filters && Filters.Filters.boundaries && Array.isArray(Filters.Filters.boundaries) && Filters.Filters.boundaries.length > 0) { const filteredBoundaryData = await generateFilteredBoundaryData( @@ -725,6 +844,66 @@ async function getBoundarySheetData( } } +async function getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement(request: any, localizationMap?: { [key: string]: string }) { + try { + const mdmsResponse = await callMdmsTypeSchema( + request, + request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, + false, + request?.query?.type || request?.body?.ResourceDetails?.type, + "all" + ); + if (!mdmsResponse || mdmsResponse?.columns.length === 0) { + logger.error( + `Campaign Type all has not any columns configured in schema` + ); + throwError( + "COMMON", + 400, + "SCHEMA_ERROR", + `Campaign Type all has not any columns configured in schema` + ); + } + // Extract columns from the response + const columnsForGivenCampaignId = mdmsResponse?.columns; + + // Get localized headers based on the column names + const headerColumnsAfterHierarchy = getLocalizedHeaders( + columnsForGivenCampaignId, + localizationMap + ); + if ( + !headerColumnsAfterHierarchy.includes( + getLocalizedName(config.boundary.boundaryCode, localizationMap) + ) + ) { + logger.error( + `Column Headers of generated Boundary Template does not have ${getLocalizedName( + config.boundary.boundaryCode, + localizationMap + )} column` + ); + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `Column Headers of generated Boundary Template does not have ${getLocalizedName( + config.boundary.boundaryCode, + localizationMap + )} column` + ); + } + return headerColumnsAfterHierarchy; + } catch (error: any) { + console.log(error); + throwError( + "FILE", + 400, + "FETCHING_COLUMN_ERROR", + "Error fetching column Headers From Schema (either boundary code column not found or given Campaign Type not found in schema) Check logs" + ); + } +} async function createStaff(resouceBody: any) { // Create staff const staffCreateUrl = @@ -806,44 +985,63 @@ async function createProjectFacility(resouceBody: any) { } // Helper function to create staff -const createStaffHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { - const ProjectStaff = { - tenantId: tenantId.split(".")?.[0], - projectId, - userId: resourceId, - startDate, - endDate, - }; - const newResourceBody = { ...resouceBody, ProjectStaff }; - return createStaff(newResourceBody); +const createProjectStaffHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { + try { + const ProjectStaff = { + tenantId: tenantId.split(".")?.[0], + projectId, + userId: resourceId, + startDate, + endDate, + }; + const newResourceBody = { ...resouceBody, ProjectStaff }; + return createStaff(newResourceBody); + } catch (error) { + // Log the error if the API call fails + logger.error(`Failed to create project staff for staffId ${resourceId}:`, error); + throw error; // Rethrow the error to propagate it + } }; // Helper function to create project resource const createProjectResourceHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { - const ProjectResource = { - tenantId: tenantId.split(".")?.[0], - projectId, - resource: { - productVariantId: resourceId, - type: "DRUG", - isBaseUnitVariant: false, - }, - startDate, - endDate, - }; - const newResourceBody = { ...resouceBody, ProjectResource }; - return createProjectResource(newResourceBody); + try { + const ProjectResource = { + tenantId: tenantId.split(".")?.[0], + projectId, + resource: { + productVariantId: resourceId, + type: "DRUG", + isBaseUnitVariant: false, + }, + startDate, + endDate, + }; + const newResourceBody = { ...resouceBody, ProjectResource }; + return createProjectResource(newResourceBody); + } + catch (error) { + // Log the error if the API call fails + logger.error(`Failed to create project resource for resourceId ${resourceId}:`, error); + throw error; // Rethrow the error to propagate it + } }; // Helper function to create project facility -const createProjectFacilityHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any) => { - const ProjectFacility = { - tenantId: tenantId.split(".")?.[0], - projectId, - facilityId: resourceId, - }; - const newResourceBody = { ...resouceBody, ProjectFacility }; - return createProjectFacility(newResourceBody); +const createProjectFacilityHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { + try { + const ProjectFacility = { + tenantId: tenantId.split(".")?.[0], + projectId, + facilityId: resourceId, + }; + const newResourceBody = { ...resouceBody, ProjectFacility }; + return createProjectFacility(newResourceBody); + } catch (error) { + // Log the error if the API call fails + logger.error(`Failed to create facility for facilityId ${resourceId}:`, error); + throw error; // Rethrow the error to propagate it + } }; @@ -880,7 +1078,7 @@ async function createRelatedEntity( mappingArray.push(mappingObject) } } - const mappingObject: any = { mappingArray: mappingArray, CampaignDetails: CampaignDetails, RequestInfo: requestBody?.RequestInfo } + const mappingObject: any = { mappingArray: mappingArray, CampaignDetails: CampaignDetails, RequestInfo: requestBody?.RequestInfo, parentCampaign: requestBody?.parentCampaign } await processMapping(mappingObject) } @@ -998,7 +1196,7 @@ async function confirmBoundaryParentCreation(request: any, code: any) { var boundaryFound = false; const header = { ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + // cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes.replace(/’/g, '') || ''}${params?.includeChildren || ''}`, } while (!boundaryFound && retry >= 0) { const response = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, searchBody, params, undefined, undefined, header); @@ -1041,7 +1239,7 @@ async function createBoundaryRelationship(request: any, boundaryMap: Map<{ key: }; const header = { ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + // cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, } const boundaryRelationshipResponse = await httpRequest(url, request.body, params, undefined, undefined, header); @@ -1122,12 +1320,12 @@ async function callMdmsData( ], }, }; - const url = config.host.mdms + config.paths.mdms_v1_search; + const url = config.host.mdmsV2 + config.paths.mdms_v1_search; const response = await httpRequest(url, requestBody, { tenantId: tenantId }); return response; } -function enrichSchema(data: any, properties: any, required: any, columns: any, unique: any, columnsNotToBeFreezed: any, errorMessage: any) { +function enrichSchema(data: any, properties: any, required: any, columns: any, unique: any, columnsNotToBeFreezed: any, columnsToBeFreezed: any, columnsToHide: any, errorMessage: any) { // Sort columns based on orderNumber, using name as tie-breaker if orderNumbers are equal columns.sort((a: any, b: any) => { @@ -1156,15 +1354,19 @@ function enrichSchema(data: any, properties: any, required: any, columns: any, u data.unique = unique; data.errorMessage = errorMessage; data.columnsNotToBeFreezed = columnsNotToBeFreezed; + data.columnsToBeFreezed = columnsToBeFreezed; + data.columnsToHide = columnsToHide; } -function convertIntoSchema(data: any) { +function convertIntoSchema(data: any, isUpdate: boolean) { const properties: any = {}; const errorMessage: any = {}; const required: any[] = []; - const columns: any[] = []; + let columns: any[] = []; const unique: any[] = []; const columnsNotToBeFreezed: any[] = []; + const columnsToBeFreezed: any[] = []; + const columnsToHide: any[] = []; for (const propType of ['enumProperties', 'numberProperties', 'stringProperties']) { if (data.properties[propType] && Array.isArray(data.properties[propType]) && data.properties[propType]?.length > 0) { @@ -1185,13 +1387,40 @@ function convertIntoSchema(data: any) { if (!property?.freezeColumn || property?.freezeColumn == false) { columnsNotToBeFreezed.push(property?.name); } + if (property?.freezeColumn) { + columnsToBeFreezed.push(property?.name); + } + if (property?.hideColumn) { + columnsToHide.push(property?.name); + } // If orderNumber is missing, default to a very high number - columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 }); + if (isUpdate) { + columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 }); + } + else { + if (!property?.isUpdate) { + columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 }); + } + } } } } - enrichSchema(data, properties, required, columns, unique, columnsNotToBeFreezed, errorMessage); + + const descriptionToFieldMap: Record = {}; + + for (const [key, field] of Object.entries(properties)) { + // Cast field to `any` since it is of type `unknown` + const typedField = field as any; + + if (typedField.isRequired) { + descriptionToFieldMap[typedField.description] = key; + } + } + data.descriptionToFieldMap = descriptionToFieldMap; + + + enrichSchema(data, properties, required, columns, unique, columnsNotToBeFreezed, columnsToBeFreezed, columnsToHide, errorMessage); return data; } @@ -1200,6 +1429,7 @@ function convertIntoSchema(data: any) { async function callMdmsTypeSchema( request: any, tenantId: string, + isUpdate: boolean, type: any, campaignType = "all" ) { @@ -1223,7 +1453,7 @@ async function callMdmsTypeSchema( if (!response?.mdms?.[0]?.data) { throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during schema search"); } - return convertIntoSchema(response?.mdms?.[0]?.data); + return convertIntoSchema(response?.mdms?.[0]?.data, isUpdate); } async function getMDMSV1Data(request: any, moduleName: string, masterName: string, tenantId: string) { @@ -1255,6 +1485,8 @@ export { getMDMSV1Data, callMdmsTypeSchema, getSheetDataFromWorksheet, - createStaffHelper, - createProjectFacilityHelper, createProjectResourceHelper + createProjectStaffHelper, + createProjectFacilityHelper, createProjectResourceHelper, + createAndUploadJsonFile, + getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement }; diff --git a/health-services/project-factory/src/server/api/healthApis.ts b/health-services/project-factory/src/server/api/healthApis.ts new file mode 100644 index 00000000000..0a2b0c8b0de --- /dev/null +++ b/health-services/project-factory/src/server/api/healthApis.ts @@ -0,0 +1,28 @@ +import { httpRequest } from "../utils/request"; +import { defaultRequestInfo } from "./coreApis"; +import config from "../config"; +import { throwError } from "../utils/genericUtils"; +import { logger } from "../utils/logger"; + +export async function fetchProductVariants(pvarIds: string[]) { + const CHUNK_SIZE = 100; + const allProductVariants: any[] = []; + const params: any = { limit: CHUNK_SIZE, offset: 0, tenantId: defaultRequestInfo?.RequestInfo?.userInfo?.tenantId }; + + for (let i = 0; i < pvarIds.length; i += CHUNK_SIZE) { + const chunk = pvarIds.slice(i, i + CHUNK_SIZE); + try { + const response = await httpRequest( + config.host.productHost + config.paths.productVariantSearch, + { ProductVariant: { id: chunk }, ...defaultRequestInfo }, + params + ); + allProductVariants.push(...response?.ProductVariant || []); + } catch (error: any) { + logger.error("Error during product variant fetch"); + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", `Some error occurred while fetching product variants. ${error?.message}`); + } + } + + return allProductVariants; // Return the fetched product variants +} diff --git a/health-services/project-factory/src/server/api/microplanApis.ts b/health-services/project-factory/src/server/api/microplanApis.ts new file mode 100644 index 00000000000..0dc0bcb97eb --- /dev/null +++ b/health-services/project-factory/src/server/api/microplanApis.ts @@ -0,0 +1,124 @@ +import config from "../config"; // Import configuration settings +import { httpRequest } from "../utils/request"; // Import httpRequest function for making HTTP requests +import { logger } from "../utils/logger"; // Import logger for logging information and errors +import { defaultRequestInfo } from "./coreApis"; // Import default request information + +/** + * Searches for facilities associated with a specific plan configuration. + * @param planConfigId The unique identifier for the plan configuration. + * @param tenantId The tenant identifier for which the search is performed. + * @returns The response containing facility details for the specified plan configuration. + */ +export const searchPlanFacility = async ( + planConfigId: string, + tenantId: string +) => { + const searchBody = { + PlanFacilitySearchCriteria: { + tenantId: tenantId, + planConfigurationId: planConfigId, + }, + ...defaultRequestInfo, // Include default request metadata + }; + logger.info( + `Received a search request for plan facility with ID: ${planConfigId}` + ); + const planFacilityResponse = await httpRequest( + config.host.planServiceHost + config.paths.planFacilitySearch, // Construct the request URL + searchBody // Pass the request body + ); + return planFacilityResponse?.PlanFacility; // Return the response from the facility search +}; + +/** + * Searches for plans based on configuration, tenant, and boundaries. + * @param planConfigId The unique identifier for the plan configuration. + * @param tenantId The tenant identifier for which the search is performed. + * @param boundaries The jurisdiction or boundary information for the search. + * @returns The response containing plan details for the specified criteria. + */ +export const searchPlan = async ( + planConfigId: string, + tenantId: string, + limit:number=1 +) => { + const searchBody = { + PlanSearchCriteria: { + tenantId: tenantId, + active: true, // Search only active plans + // jurisdiction: boundaries, // Specify jurisdiction for the search + planConfigurationId: planConfigId, + limit: limit, // Limit the response to 1 result + offset: 0, // Start from the first result + }, + ...defaultRequestInfo, // Include default request metadata + }; + logger.info( + `Received a search request for plans with ID: ${planConfigId}` + ); + const planResponse = await httpRequest( + config.host.planServiceHost + config.paths.planSearch, // Construct the request URL + searchBody // Pass the request body + ); + return planResponse?.Plan; // Return the response from the plan search +}; + +/** + * Searches for census data related to a specific plan configuration and boundary codes. + * @param planConfigId The unique identifier for the plan configuration. + * @param tenantId The tenant identifier for which the search is performed. + * @param boundaryCodes The area codes defining the search boundaries. + * @returns The response containing census details for the specified criteria. + */ +export const searchPlanCensus = async ( + planConfigId: string, + tenantId: string, + limit:number=1 +) => { + const searchBody = { + CensusSearchCriteria: { + tenantId: tenantId, + source: planConfigId, // Use planConfigId as the source of the census data + // areaCodes: boundaryCodes, // Specify area codes for the search + offset:0, + limit:limit, + }, + + ...defaultRequestInfo, // Include default request metadata + }; + logger.info( + `Received a search request for census data with ID: ${planConfigId}` + ); + const planCensusResponse = await httpRequest( + config.host.censusServiceHost + config.paths.censusSearch, // Construct the request URL + searchBody // Pass the request body + ); + return planCensusResponse?.Census; // Return the response from the census search +}; + +/** + * Searches for plan configuration details based on configuration ID and tenant. + * @param planConfigId The unique identifier for the plan configuration. + * @param tenantId The tenant identifier for which the search is performed. + * @returns The response containing configuration details for the specified plan configuration. + */ +export const searchPlanConfig = async ( + planConfigId: string, + tenantId: string +) => { + const searchBody = { + PlanConfigurationSearchCriteria: { + tenantId: tenantId, + id: planConfigId, // Specify the plan configuration ID + }, + ...defaultRequestInfo, // Include default request metadata + }; + logger.info( + `Received a search request for plan configuration with ID: ${planConfigId}` + ); + const planConfigResponse = await httpRequest( + config.host.planServiceHost + config.paths.planConfigSearch, // Construct the request URL + searchBody // Pass the request body + ); + return planConfigResponse; // Return the response from the plan configuration search +}; diff --git a/health-services/project-factory/src/server/app.ts b/health-services/project-factory/src/server/app.ts index a51c4ab15bd..f662b76d104 100644 --- a/health-services/project-factory/src/server/app.ts +++ b/health-services/project-factory/src/server/app.ts @@ -1,10 +1,21 @@ -import express from 'express'; -import * as bodyParser from 'body-parser'; -import config from './config'; -import { requestMiddleware } from './utils/middlewares'; -import { errorLogger, errorResponder, invalidPathHandler } from './utils/genericUtils'; -import { tracingMiddleware } from './tracing'; -import { createProxyMiddleware } from 'http-proxy-middleware'; +import express from "express"; +import * as bodyParser from "body-parser"; +import config from "./config"; +import { requestMiddleware } from "./utils/middlewares"; +import { + errorLogger, + errorResponder, + invalidPathHandler, +} from "./utils/genericUtils"; +import { tracingMiddleware } from "./tracing"; +import { createProxyMiddleware } from "http-proxy-middleware"; +import * as v8 from "v8"; +import { logger } from "./utils/logger"; + +const printMemoryInMB = (memoryInBytes: number) => { + const memoryInMB = memoryInBytes / (1024 * 1024); // Convert bytes to MB + return `${memoryInMB.toFixed(2)} MB`; +}; class App { public app: express.Application; @@ -17,21 +28,43 @@ class App { this.initializeMiddlewares(); this.initializeControllers(controllers); this.app.use(invalidPathHandler); + + // Global error handling for uncaught exceptions + process.on("uncaughtException", (err) => { + console.error("Unhandled Exception:", err); + }); + + // Global error handling for unhandled promise rejections + process.on("unhandledRejection", (reason, promise) => { + console.error("Unhandled Rejection at:", promise, "reason:", reason); + }); } private initializeMiddlewares() { + this.app.use( + bodyParser.json({ limit: config.app.incomingRequestPayloadLimit }) + ); + this.app.use( + bodyParser.urlencoded({ + limit: config.app.incomingRequestPayloadLimit, + extended: true, + }) + ); this.app.use(bodyParser.json()); this.app.use(tracingMiddleware); this.app.use(requestMiddleware); this.app.use(errorLogger); this.app.use(errorResponder); - this.app.use('/tracing', createProxyMiddleware({ - target: 'http://localhost:16686', - changeOrigin: true, - pathRewrite: { - '^/tracing': '/', - }, - })); + this.app.use( + "/tracing", + createProxyMiddleware({ + target: "http://localhost:16686", + changeOrigin: true, + pathRewrite: { + "^/tracing": "/", + }, + }) + ); } private initializeControllers(controllers: any) { @@ -42,7 +75,34 @@ class App { public listen() { this.app.listen(this.port, () => { - console.log(`App listening on the port ${this.port}`); + logger.info(`App listening on the port ${this.port}`); + // Add periodic monitoring + setInterval(() => { + const stats = v8.getHeapStatistics(); + const usedHeapSize = stats.used_heap_size; + const heapLimit = stats.heap_size_limit; + + logger.debug( + JSON.stringify({ + "Heap Usage": { + used: printMemoryInMB(usedHeapSize), + limit: printMemoryInMB(heapLimit), + percentage: ((usedHeapSize / heapLimit) * 100).toFixed(2), + }, + }) + ); + + // Alert if memory usage is above 80% + if (usedHeapSize / heapLimit > 0.8) { + logger.warn("High memory usage detected"); + } + }, 5 * 60 * 1000); // Every 5 minutes + logger.info( + "Current App's Heap Configuration Total Available :", + printMemoryInMB(v8.getHeapStatistics()?.total_available_size), + " max limit set to : ", + printMemoryInMB(v8.getHeapStatistics()?.heap_size_limit) + ); }); } } diff --git a/health-services/project-factory/src/server/config/constants.ts b/health-services/project-factory/src/server/config/constants.ts index 5023c9de00b..73178392f23 100644 --- a/health-services/project-factory/src/server/config/constants.ts +++ b/health-services/project-factory/src/server/config/constants.ts @@ -34,7 +34,11 @@ export const CONSTANTS: any = { GENERATION_REQUIRE: "First generate then download", RESOURCE_CREATION_ERROR: "Some error occured during resource creation", CAMPAIGN_NAME_ERROR: "Campaign name already exists", + CAMPAIGN_NAME_NOT_MATCHING_PARENT_ERROR: "Campaign name different from parent Campaign", CAMPAIGN_ALREADY_MAPPED: "Campaign is already mapped", + PARENT_CAMPAIGN_ERROR: "Parent Camapign error ", + INVALID_RESOURCE_DISTRIBUTION_STRATEGY: "Invalid resource distribution strategy", + RESOURCES_CONSOLIDATION_ERROR : "Error while consolidating resources in Campaign Update Flow " }, BOUNDARY: { BOUNDARY_DATA_NOT_FOUND: "No boundary data found in the system.", @@ -45,7 +49,9 @@ export const CONSTANTS: any = { BOUNDARY_ENTITY_CREATE_ERROR: "Some error occured during boundary entity creation", BOUNDARY_RELATIONSHIP_CREATE_ERROR: "Some error occured during boundary relationship creation", BOUNDARY_TARGET_ERROR: "Target either not present or invalid value", - BOUNDARY_CONFIRMATION_FAILED: "Error in boundary creation and persistence" + BOUNDARY_CONFIRMATION_FAILED: "Error in boundary creation and persistence", + BOUNDARY_SHEET_UPLOADED_INVALID_ERROR: "Error in the boundary data uploaded", + BOUNDARY_SHEET_FIRST_COLUMN_INVALID_ERROR: "First Column Of Boundary Sheet uploaded should be unique as it is the root of hierarchy" }, PROJECT: { PROJECT_CREATION_FAILED: "Error occured in project creation", @@ -53,10 +59,17 @@ export const CONSTANTS: any = { PROJECT_UPDATE_ERROR: "Error occured during project update , check projectId", PROJECT_CREATION_ERROR: "Some error occured during project creation", PROJECT_CONFIRMATION_FAILED: "Error occured in project creation and peristence", + PROJECT_STAFF_SEARCH_ERROR: "Error occured during project search , check projectId and staffId", + PROJECT_FACILITY_SEARCH_ERROR: "Error occured during project search , check projectId and facilityId", + PROJECT_FACILITY_DELETE_ERROR: "Error occured while deleting project facility mapping", + PROJECT_STAFF_DELETE_ERROR: "Error occured while deleting project staff mapping" }, MDMS: { INVALID_README_CONFIG: "Invalid readme config", MDMS_DATA_NOT_FOUND_ERROR: "Mdms Data not present" + }, + DATA:{ + DATA_CREATE_ERROR : "Error while creating resource data" } } } @@ -144,8 +157,6 @@ export const processTrackStatuses = { toBeCompleted: "toBeCompleted", failed: "failed", } - - // Retrieves the error object containing the error code, message, and notFound flag. export const getErrorCodes = (module: string, key: string): Error => { // Retrieve the error message from the CONSTANTS object @@ -160,4 +171,4 @@ export const getErrorCodes = (module: string, key: string): Error => { notFound: true, message: message } -} +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/config/createAndSearch.ts b/health-services/project-factory/src/server/config/createAndSearch.ts index 8fb63b1be9f..31f801d7e59 100644 --- a/health-services/project-factory/src/server/config/createAndSearch.ts +++ b/health-services/project-factory/src/server/config/createAndSearch.ts @@ -8,7 +8,7 @@ const createAndSearch: any = { } ], boundaryValidation: { - column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", }, sheetSchema: { "$schema": "http://json-schema.org/draft-07/schema#", @@ -140,7 +140,7 @@ const createAndSearch: any = { } ], boundaryValidation: { - column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + column: "HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN" }, sheetSchema: { "$schema": "http://json-schema.org/draft-07/schema#", @@ -270,8 +270,13 @@ const createAndSearch: any = { } }, "user": { + requiresToSearchFromSheet: [ + { + sheetColumnName: "UserService Uuids", + searchPath: "user.mobileNumber" + }], boundaryValidation: { - column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", }, sheetSchema: { "$schema": "http://json-schema.org/draft-07/schema#", @@ -349,8 +354,10 @@ const createAndSearch: any = { } }, uniqueIdentifier: "user.userServiceUuid", - uniqueIdentifierColumn: "H", + uniqueIdentifierColumn: "I", uniqueIdentifierColumnName: "UserService Uuids", + activeColumn: "F", + activeColumnName: "HCM_ADMIN_CONSOLE_USER_USAGE", createBulkDetails: { limit: 50, createPath: "Employees", @@ -388,6 +395,14 @@ const createAndSearch: any = { boundaryValidation: { column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE" } + }, + "boundaryManagement": { + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", + }, + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE" + } } } diff --git a/health-services/project-factory/src/server/config/index.ts b/health-services/project-factory/src/server/config/index.ts index 7260b93c59d..874618bcb84 100644 --- a/health-services/project-factory/src/server/config/index.ts +++ b/health-services/project-factory/src/server/config/index.ts @@ -12,34 +12,36 @@ if (!HOST) { const getDBSchemaName = (dbSchema = "") => { + // return "health"; return dbSchema ? (dbSchema == "egov" ? "public" : dbSchema) : "public"; } // Configuration object containing various environment variables const config = { - cacheTime : 300, + batchSize:100, + cacheTime: 300, + isProduction: process.env ? true : false, + token: "", // add default token if core services are not port forwarded enableDynamicTemplateFor: process.env.ENABLE_DYNAMIC_TEMPLATE_FOR || "", isCallGenerateWhenDeliveryConditionsDiffer: (process.env.IS_CALL_GENERATE_WHEN_DELIVERY_CONDITIONS_DIFFER === "true") || false, prefixForMicroplanCampaigns: "MP", excludeHierarchyTypeFromBoundaryCodes: (process.env.EXCLUDE_HIERARCHY_TYPE_FROM_BOUNDARY_CODES === "true") || false, excludeBoundaryNameAtLastFromBoundaryCodes: (process.env.EXCLUDE_BOUNDARY_NAME_AT_LAST_FROM_BOUNDARY_CODES === "true") || false, masterNameForSchemaOfColumnHeaders: "adminSchema", - masterNameForSplitBoundariesOn: "hierarchyConfig", + masterNameForSplitBoundariesOn: "HierarchySchema", boundary: { boundaryCode: process.env.BOUNDARY_CODE_HEADER_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", + boundaryCodeMandatory: 'HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY', + boundaryCodeOld: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", boundaryTab: process.env.BOUNDARY_TAB_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", - // Default criteria for generating different tabs - generateDifferentTabsOnBasisOf: process.env.SPLIT_BOUNDARIES_ON || "ADMIN_DISTRITO", // default configurable number of data of boundary type on which generate different tabs numberOfBoundaryDataOnWhichWeSplit: process.env.SPLIT_BOUNDARIES_ON_LENGTH || "2", boundaryRelationShipDelay: 3500 }, facility: { facilityTab: process.env.FACILITY_TAB_NAME || "HCM_ADMIN_CONSOLE_FACILITIES", - facilitySchemaMasterName: process.env.FACILITY_SCHEMA_MASTER || "facilitySchema", }, user: { userTab: process.env.USER_TAB_NAME || "HCM_ADMIN_CONSOLE_USER_LIST", - userSchemaMasterName: process.env.USER_SCHEMA_MASTER || "userSchema", userDefaultPassword: process.env.USER_DEFAULT_PASSWORD || "eGov@123", userPasswordAutoGenerate: process.env.USER_PASSWORD_AUTO_GENERATE || "true", mapUserViaCommonParent: process.env.MAP_USER_VIA_COMMON_PARENT || false, @@ -62,6 +64,7 @@ const config = { KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC || "create-generated-resource-details", KAFKA_SAVE_PROCESS_TRACK_TOPIC: process.env.KAFKA_SAVE_PROCESS_TRACK_TOPIC || "save-process-track", KAFKA_UPDATE_PROCESS_TRACK_TOPIC: process.env.KAFKA_UPDATE_PROCESS_TRACK_TOPIC || "update-process-track", + KAFKA_SAVE_PLAN_FACILITY_TOPIC: process.env.KAFKA_SAVE_PLAN_FACILITY_TOPIC || "project-factory-save-plan-facility", KAFKA_TEST_TOPIC: "test-topic-project-factory", }, @@ -83,12 +86,15 @@ const config = { host: HOST, contextPath: process.env.CONTEXT_PATH || "/project-factory", logLevel: process.env.APP_LOG_LEVEL || "debug", - debugLogCharLimit: process.env.APP_MAX_DEBUG_CHAR ? Number(process.env.APP_MAX_DEBUG_CHAR) : 1000 + debugLogCharLimit: process.env.APP_MAX_DEBUG_CHAR ? Number(process.env.APP_MAX_DEBUG_CHAR) : 1000, + defaultTenantId: process.env.DEFAULT_TENANT_ID || "mz", + // incomingRequestPayloadLimit : process.env.REQUEST_PAYLOAD_LIMIT || "2mb" @ashish add this key and config helm chart values + incomingRequestPayloadLimit: "2mb" }, localisation: { defaultLocale: process.env.LOCALE || "en_MZ", - boundaryPrefix: "rainmaker-boundary", - localizationModule: process.env.LOCALIZATION_MODULE || "rainmaker-hcm-admin-schemas", + boundaryPrefix: "hcm-boundary", + localizationModule: process.env.LOCALIZATION_MODULE || "hcm-admin-schemas", }, // targetColumnsForSpecificCampaigns: { // bedNetCampaignColumns: ["HCM_ADMIN_CONSOLE_TARGET"], @@ -113,12 +119,14 @@ const config = { hrmsHost: process.env.EGOV_HRMS_HOST || "https://unified-dev.digit.org/", localizationHost: process.env.EGOV_LOCALIZATION_HOST || "https://unified-dev.digit.org/", healthIndividualHost: process.env.EGOV_HEALTH_INDIVIDUAL_HOST || "https://unified-dev.digit.org/", - }, + planServiceHost: process.env.EGOV_PLAN_SERVICE_HOST || "https://unified-dev.digit.org/", + censusServiceHost: process.env.EGOV_CENSUS_HOST ||"https://unified-dev.digit.org/", }, // Paths for different services paths: { filestore: process.env.FILE_STORE_SERVICE_END_POINT || "filestore/v1/files", - mdms_search: process.env.EGOV_MDMS_SEARCH_ENDPOINT || "egov-mdms-service/v2/_search", - mdms_v1_search: process.env.EGOV_MDMS_V1_SEARCH_ENDPOINT || "egov-mdms-service/v1/_search", + filestorefetch: "filestore/v1/files/url", + mdms_v2_search: process.env.EGOV_MDMS_V2_SEARCH_ENDPOINT || "mdms-v2/v2/_search", + mdms_v1_search: process.env.EGOV_MDMS_V1_SEARCH_ENDPOINT || "mdms-v2/v1/_search", idGen: process.env.EGOV_IDGEN_PATH || "egov-idgen/id/_generate", mdmsSchema: process.env.EGOV_MDMS_SCHEMA_PATH || "egov-mdms-service/schema/v1/_search", boundaryRelationship: process.env.EGOV_BOUNDARY_RELATIONSHIP_SEARCHPATH || "boundary-service/boundary-relationships/_search", @@ -141,27 +149,36 @@ const config = { localizationCreate: "localization/messages/v1/_upsert", projectTypeSearch: "project-factory/v1/project-type/search", boundaryRelationshipCreate: "boundary-service/boundary-relationships/_create", - mdmsV2SchemaSearch: "mdms-v2/schema/v1/_search", - mdms_v2_search: "mdms-v2/v2/_search", healthIndividualSearch: process.env.EGOV_HEALTH_INDIVIDUAL_SEARCH || "health-individual/v1/_search", - }, + projectFacilitySearch: process.env.EGOV_HEALTH_PROJECT_FACILITY_SEARCH || "health-project/facility/v1/_search", + projectStaffSearch: process.env.EGOV_HEALTH_PROJECT_STAFF_SEARCH || "health-project/staff/v1/_search", + projectFacilityDelete: process.env.EGOV_HEALTH_PROJECT_FACILITY_BULK_DELETE || "health-project/facility/v1/bulk/_delete", + projectStaffDelete: process.env.EGOV_HEALTH_PROJECT_STAFF_BULK_DELETE || "health-project/staff/v1/bulk/_delete", + planFacilitySearch: process.env.EGOV_PLAN_FACILITY_SEARCH || "plan-service/plan/facility/_search", + planConfigSearch: process.env.EGOV_PLAN_FACILITY_CONFIG_SEARCH || "plan-service/config/_search", + planSearch: process.env.EGOV_PLAN_SEARCH || "plan-service/plan/_search", + censusSearch: process.env.EGOV_CENSUS_SEARCH || "census-service/_search" }, // Values configuration values: { //module name unfrozeTillRow: process.env.UNFROZE_TILL_ROW || "10000", unfrozeTillColumn: process.env.UNFROZE_TILL_COLUMN || "50", moduleName: process.env.MODULE_NAME || "HCM-ADMIN-CONSOLE", - readMeTab: "HCM_README_SHEETNAME", + readMeTab: process.env.READ_ME_TAB || "HCM_README_SHEETNAME", userMainBoundary: "mz", userMainBoundaryType: "Country", idgen: { format: process.env.CMP_IDGEN_FORMAT || "CMP-[cy:yyyy-MM-dd]-[SEQ_EG_CMP_ID]", - idName: process.env.CMP_IDGEN_IDNAME || "campaign.number" + idName: process.env.CMP_IDGEN_IDNAME || "campaign.number", + idNameForUserNameGeneration: "username.name", + formatForUserName: "USR-[SEQ_EG_USER_NAME]" }, matchFacilityData: false, retryCount: process.env.CREATE_RESOURCE_RETRY_COUNT || "3", notCreateUserIfAlreadyThere: process.env.NOT_CREATE_USER_IF_ALREADY_THERE || false, - maxHttpRetries: process.env.MAX_HTTP_RETRIES || "4" + maxHttpRetries: process.env.MAX_HTTP_RETRIES || "4", + skipResourceCheckValidationBeforeCreateForLocalTesting:false, // can be set to true for local development + autoRetryIfHttpError: process.env.AUTO_RETRY_IF_HTTP_ERROR || "socket hang up" // can be retry if there is any error for which default retry can be set } }; // Exporting getErrorCodes function and config object diff --git a/health-services/project-factory/src/server/config/models/SearchCriteria.ts b/health-services/project-factory/src/server/config/models/SearchCriteria.ts index 54d30a7d0e1..d5acc896484 100644 --- a/health-services/project-factory/src/server/config/models/SearchCriteria.ts +++ b/health-services/project-factory/src/server/config/models/SearchCriteria.ts @@ -17,6 +17,9 @@ export const searchCriteriaSchema = { }, "status": { "type": "string" + }, + "hierarchyType": { + "type": "string" } }, "required": ["tenantId"], diff --git a/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts b/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts index 873d2b5d034..61de751134b 100644 --- a/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts +++ b/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts @@ -19,7 +19,7 @@ export const campaignDetailsDraftSchema = { }, "action": { "type": "string", - "enum": ["create", "draft"], + "enum": ["create", "draft", "retry"], "maxLength": 64, "minLength": 1 }, @@ -92,6 +92,9 @@ export const campaignDetailsDraftSchema = { }, "additionalDetails": { "type": "object" + }, + "isActive":{ + "type":"boolean" } }, "required": ["tenantId", "campaignName", "hierarchyType"] diff --git a/health-services/project-factory/src/server/config/models/createRequestSchema.ts b/health-services/project-factory/src/server/config/models/createRequestSchema.ts index 18a96101fbd..2f9b36bc136 100644 --- a/health-services/project-factory/src/server/config/models/createRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/createRequestSchema.ts @@ -4,7 +4,7 @@ export const createRequestSchema = { "properties": { "type": { "type": "string", - "enum": ["boundary", "facility", "user", "boundaryWithTarget","facilityMicroplan"] + "enum": ["boundary", "facility", "user", "boundaryWithTarget", "facilityMicroplan","boundaryManagement", "boundaryGeometryManagement"] }, "tenantId": { "type": "string", @@ -32,6 +32,9 @@ export const createRequestSchema = { }, "additionalDetails": { "type": "object" + }, + "isActive":{ + "type":"boolean" } }, "required": ["type", "tenantId", "fileStoreId", "action", "hierarchyType"], diff --git a/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts index d23b7df2f4f..759e3aa9d36 100644 --- a/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts @@ -16,7 +16,9 @@ export const downloadRequestSchema = { "user", "boundary", "facilityWithBoundary", - "userWithBoundary" + "userWithBoundary", + "boundaryManagement", + "boundaryGeometryManagement" ] }, "hierarchyType": { diff --git a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts index 4ca530f9393..1413905173a 100644 --- a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts @@ -13,8 +13,10 @@ export const generateRequestSchema = { "minLength": 1, "enum": [ "boundary", + "boundaryManagement", "facilityWithBoundary", - "userWithBoundary" + "userWithBoundary", + "boundaryGeometryManagement" ] }, "hierarchyType": { @@ -28,6 +30,9 @@ export const generateRequestSchema = { }, "campaignId": { "type": "string" + }, + "source": { + "type": "string", } }, "required": ["tenantId", "type", "hierarchyType", "campaignId"], diff --git a/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts b/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts index 155e8babbc4..8f4588ad79b 100644 --- a/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts +++ b/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts @@ -9,6 +9,9 @@ export const searchCampaignDetailsSchema = { "type": "string" } }, + "isActive":{ + "type":"boolean" + }, "tenantId": { "type": "string", "minLength": 1 diff --git a/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts index dc3232294e2..1fd3e0646ea 100644 --- a/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts +++ b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts @@ -1,7 +1,16 @@ import * as express from "express"; -import { createCampaignService, createProjectTypeCampaignService, searchProcessTracksService, searchProjectTypeCampaignService, updateProjectTypeCampaignService } from "../../service/campaignManageService"; +import { + createCampaignService, + createProjectTypeCampaignService, + fetchFromMicroplanService, + retryProjectTypeCampaignService, + searchProcessTracksService, + searchProjectTypeCampaignService, + updateProjectTypeCampaignService +} from "../../service/campaignManageService"; import { logger } from "../../utils/logger"; import { errorResponder, sendResponse } from "../../utils/genericUtils"; +import { validateSearchProjectCampaignRequest } from "../../validators/campaignValidators"; @@ -22,9 +31,13 @@ class campaignManageController { this.router.post(`${this.path}/create`, this.createProjectTypeCampaign); this.router.post(`${this.path}/update`, this.updateProjectTypeCampaign); this.router.post(`${this.path}/search`, this.searchProjectTypeCampaign); + this.router.post(`${this.path}/retry`, this.retryProjectTypeCampaign); this.router.post(`${this.path}/createCampaign`, this.createCampaign); this.router.post(`${this.path}/getProcessTrack`, this.searchProcessTracks); + this.router.post(`${this.path}/fetch-from-microplan`, this.fetchFromMicroplan); } + + /** * Handles the creation of a project type campaign. * @param request The Express request object. @@ -78,7 +91,9 @@ class campaignManageController { ) => { try { logger.info("RECEIVED A PROJECT TYPE SEARCH REQUEST"); - const responseBody = await searchProjectTypeCampaignService(request); + // Validate the search request for project type campaigns + await validateSearchProjectCampaignRequest(request); + const responseBody = await searchProjectTypeCampaignService(request?.body?.CampaignDetails); // Send response with campaign details and total count return sendResponse(response, responseBody, request); } catch (e: any) { @@ -130,7 +145,40 @@ class campaignManageController { } }; + retryProjectTypeCampaign = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROJECT TYPE RETRY REQUEST"); + const CampaignDetails = await retryProjectTypeCampaignService(request); + return sendResponse(response, { CampaignDetails }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + } + + fetchFromMicroplan = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A FETCH FROM MICROPLAN REQUEST"); + const CampaignDetails = await fetchFromMicroplanService(request); + return sendResponse(response, { CampaignDetails }, request); + } + catch (e: any) { + console.log(e) + logger.error(String(e)) + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + } + }; + export default campaignManageController; diff --git a/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts index 3591c1c016c..e8f97f90f5d 100644 --- a/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts +++ b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts @@ -15,7 +15,7 @@ class Localisation { // Hold the single instance of the class private static instance: Localisation; constructor() { - this.localizationHost = config.host.localizationHost + this.localizationHost = config.host.localizationHost; } // Public method to provide access to the single instance public static getInstance(): Localisation { @@ -36,12 +36,13 @@ class Localisation { public getLocalisedData: any = async ( module: string, locale: string, - tenantId: string + tenantId: string, + overrideCache: boolean ) => { logger.info( `Checks Localisation message is available in cache for module ${module}, locale ${locale}, tenantId ${tenantId}` ); - if (!this?.cachedResponse?.[`${module}-${locale}`]) { + if (!this?.cachedResponse?.[`${module}-${locale}`] || overrideCache) { logger.info(`Not found in cache`); await this.fetchLocalisationMessage(module, locale, tenantId); } @@ -82,6 +83,20 @@ class Localisation { cachedResponse = { ...this.cachedResponse }; }; + private checkCacheAndDeleteIfExists = (module: string, locale: "string") => { + logger.info( + `Received to checkCacheAndDeleteIfExists for module ${module}, locale ${locale}` + ); + if (this.cachedResponse?.[`${module}-${locale}`]) { + logger.info(`cache found to for module ${module}, locale ${locale}`); + if (delete this.cachedResponse?.[`${module}-${locale}`]) { + logger.info( + `cache deleted for module ${module}, locale ${locale}, since new data has been created` + ); + } + } + }; + /** * Create localisation entries by sending a POST request to the localization host. * @param messages - Array of localisation messages to be created. @@ -98,13 +113,19 @@ class Localisation { // Construct request body with RequestInfo and localisation messages const requestBody = { RequestInfo, messages, tenantId }; // Construct URL for localization create endpoint - const url = - this.localizationHost + config.paths.localizationCreate; + const url = this.localizationHost + config.paths.localizationCreate; // Log the start of the localisation messages creation process - logger.info("Creating the localisation messages"); + logger.info(`Creating the localisation messages of count ${messages?.length}`); // Send HTTP POST request to create localisation messages await httpRequest(url, requestBody); + + messages && + messages?.length > 0 && + this.checkCacheAndDeleteIfExists( + messages?.[0]?.module, + messages?.[0]?.locale + ); // Log the completion of the localisation messages creation process logger.info("Localisation messages created successfully"); } catch (e: any) { diff --git a/health-services/project-factory/src/server/kafka/Producer.ts b/health-services/project-factory/src/server/kafka/Producer.ts index dc19acc2fa1..cafa0ac6f66 100644 --- a/health-services/project-factory/src/server/kafka/Producer.ts +++ b/health-services/project-factory/src/server/kafka/Producer.ts @@ -1,5 +1,5 @@ import { Producer, KafkaClient } from 'kafka-node'; -import { logger } from "../utils/logger"; +import { getFormattedStringForDebug, logger } from "../utils/logger"; import { shutdownGracefully, throwError } from '../utils/genericUtils'; import config from '../config'; @@ -57,31 +57,31 @@ const checkBrokerAvailability = () => { createKafkaClientAndProducer(); -const sendWithRetries = (payloads: any[], retries = 3, shutdown: boolean = false): Promise => { +const sendWithReconnect = (payloads: any[]): Promise => { return new Promise((resolve, reject) => { + // Send the message initially producer.send(payloads, async (err: any) => { if (err) { logger.error('Error sending message:', err); - logger.debug(`Was trying to send: ${JSON.stringify(payloads)}`); - if (retries > 0) { - logger.info(`Retrying to send message. Retries left: ${retries}`); - await new Promise(resolve => setTimeout(resolve, 2000)); // wait before retrying - resolve(sendWithRetries(payloads, retries - 1, shutdown)); - } else { - // Attempt to reconnect and retry - logger.error('Failed to send message after retries. Reconnecting producer...'); - if (shutdown) { - shutdownGracefully(); - } - else { - producer.close(() => { - createKafkaClientAndProducer(); - setTimeout(() => { - sendWithRetries(payloads, 1, true).catch(reject); - }, 2000); // wait before retrying after reconnect + logger.debug(`Was trying to send: ${getFormattedStringForDebug(payloads)}`); + + // Attempt to reconnect and retry + logger.error('Reconnecting producer and retrying...'); + producer.close(() => { + createKafkaClientAndProducer(); + setTimeout(() => { + // Retry sending after reconnection + producer.send(payloads, (err: any) => { + if (err) { + logger.error('Failed to send message after reconnection:', err); + return reject(err); // Final failure, reject promise + } else { + logger.info('Message sent successfully after reconnection'); + resolve(); + } }); - } - } + }, 2000); // wait before retrying after reconnect + }); } else { logger.info('Message sent successfully'); resolve(); @@ -90,6 +90,7 @@ const sendWithRetries = (payloads: any[], retries = 3, shutdown: boolean = false }); }; + async function produceModifiedMessages(modifiedMessages: any[], topic: any) { try { logger.info(`KAFKA :: PRODUCER :: A message sent to topic ${topic}`); @@ -101,7 +102,7 @@ async function produceModifiedMessages(modifiedMessages: any[], topic: any) { }, ]; - await sendWithRetries(payloads, 3); + await sendWithReconnect(payloads); } catch (error) { logger.error(`KAFKA :: PRODUCER :: Exception caught: ${JSON.stringify(error)}`); throwError("COMMON", 400, "KAFKA_ERROR", "Some error occurred in Kafka"); // Re-throw the error after logging it diff --git a/health-services/project-factory/src/server/models/Boundary.d.ts b/health-services/project-factory/src/server/models/Boundary.d.ts new file mode 100644 index 00000000000..576ef939992 --- /dev/null +++ b/health-services/project-factory/src/server/models/Boundary.d.ts @@ -0,0 +1,115 @@ +import { AuditDetails } from "./MDMS"; + +/** + * Represents the response structure for a boundary entity search. + */ +export interface BoundaryEntityResponse { + /** Array of boundary entities returned in the response */ + Boundary: BoundaryEntity[]; +} + +/** + * Represents a boundary entity within the MDMS system. + */ +interface BoundaryEntity { + /** Unique identifier for the boundary entity */ + id: string; + /** Tenant ID associated with the boundary entity */ + tenantId: string; + /** Unique code representing the boundary entity */ + code: string; + /** Geographical data for the boundary entity */ + geometry: any; + /** Audit information such as created/modified timestamps and users */ + auditDetails: AuditDetails; + /** Additional details related to the boundary entity */ + additionalDetails: any; +} + +/** + * Represents the response structure for a boundary hierarchy definition search. + */ +export interface BoundaryHierarchyDefinitionResponse { + /** Array of boundary hierarchy definitions in the response */ + BoundaryHierarchy: BoundaryHierarchy[]; +} + +/** + * Defines a boundary hierarchy within the MDMS system. + */ +interface BoundaryHierarchy { + /** Unique identifier for the hierarchy */ + id: string; + /** Tenant ID associated with the hierarchy */ + tenantId: string; + /** Type of hierarchy (e.g., administrative, geographic) */ + hierarchyType: string; + /** Elements representing each level within the hierarchy */ + boundaryHierarchy: BoundaryHierarchyElement[]; + /** Audit information such as created/modified timestamps and users */ + auditDetails: AuditDetails; +} + +/** + * Represents an element in the boundary hierarchy. + */ +interface BoundaryHierarchyElement { + /** Type of boundary at this level of the hierarchy */ + boundaryType: string; + /** Type of the parent boundary, if applicable */ + parentBoundaryType: null | string; + /** Indicates if the boundary is active */ + active: boolean; +} + +/** + * Represents the response structure for a boundary hierarchy relationship search. + */ +export interface BoundaryHierarchyRelationshipResponse { + /** Array of tenant boundaries returned in the response */ + TenantBoundary: TenantBoundary[]; +} + +/** + * Represents a tenant boundary structure within the MDMS system. + */ +interface TenantBoundary { + /** Tenant ID associated with this boundary */ + tenantId: string; + /** Type of hierarchy within which the boundary is categorized */ + hierarchyType: string; + /** Array of boundaries within this tenant's hierarchy */ + boundary: Boundary[]; +} + +/** + * Represents an individual boundary within a hierarchy, which may contain nested child boundaries. + */ +interface Boundary { + /** Unique identifier for the boundary */ + id: string; + /** Code representing the boundary */ + code: string; + /** Type of boundary (e.g., city, region) */ + boundaryType: string; + /** Array of child boundaries, allowing nested hierarchies */ + children: Boundary[]; +} + +/** + * Represents the search criteria for querying boundary hierarchy definitions. + */ +export interface BoundaryHierarchyDefinitionSearchCriteria { + /** Contains criteria for boundary type hierarchy search */ + BoundaryTypeHierarchySearchCriteria: BoundaryTypeHierarchySearchCriteria; +} + +/** + * Defines the criteria for searching a specific boundary type hierarchy. + */ +interface BoundaryTypeHierarchySearchCriteria { + /** Tenant ID for filtering the search results */ + tenantId: string; + /** Type of hierarchy being queried (e.g., administrative levels) */ + hierarchyType: string; +} diff --git a/health-services/project-factory/src/server/models/MDMS.d.ts b/health-services/project-factory/src/server/models/MDMS.d.ts new file mode 100644 index 00000000000..0a163e14f1c --- /dev/null +++ b/health-services/project-factory/src/server/models/MDMS.d.ts @@ -0,0 +1,144 @@ +/** + * Criteria for MDMS v1 request + */ +interface MDMSv1Criteria { + tenantId: string; // Unique identifier for the tenant + moduleDetails: ModuleDetail[]; // Array of module details to fetch +} + +/** + * Represents details of a specific module in MDMS v1 + */ +interface ModuleDetail { + moduleName: string; // Name of the module + masterDetails: MasterDetail[]; // Array of master data details for this module +} + +/** + * Details of a specific master entity in a module + */ +interface MasterDetail { + name: string; // Name of the master entity + filter?: string; // Optional filter criteria for fetching specific master data +} + +/** + * Criteria for MDMS v2 request + */ +interface MDMSv2Criteria { + tenantId: string; // Unique identifier for the tenant + schemaCode: string; // Code representing the schema to query + ids?: string[]; // Optional array of specific IDs to fetch + uniqueIdentifiers?: string[]; // Optional array of unique identifiers for the data +} + +/** + * Response structure for MDMS v1 response + */ +export interface MDMSv1Response { + MdmsRes: any; // Response payload, structure may vary +} + +/** + * Response structure for MDMS v2 response + */ +export interface MDMSv2Response { + mdms: MDMS[]; // Array of MDMS records +} + +/** + * Represents a single MDMS record in v2 response + */ +interface MDMS { + id: string; // Unique identifier for the MDMS record + tenantId: string; // Tenant identifier for the record + schemaCode: string; // Schema code associated with this record + uniqueIdentifier: string; // Unique identifier within this schema + data: any; // Data payload for the record + isActive: boolean; // Indicates if the record is active + auditDetails: AuditDetails; // Audit details for tracking changes +} + +/** + * Audit details containing metadata about record creation and modification + */ +interface AuditDetails { + createdBy: string; // ID of the user who created the record + lastModifiedBy: string; // ID of the user who last modified the record + createdTime: number; // Timestamp when the record was created + lastModifiedTime: number; // Timestamp when the record was last modified +} + +/** + * Response structure for MDMS schema definitions + */ +export interface MDMSSchemaResponse { + SchemaDefinitions: SchemaDefinition[]; // Array of schema definitions +} + +/** + * Represents a single schema definition in the MDMS response + */ +interface SchemaDefinition { + id: string; // Unique identifier for the schema definition + tenantId: string; // Tenant identifier associated with this schema + code: string; // Code identifying the schema + description: null | string; // Description of the schema, if available + definition: Definition; // Schema structure definition + isActive: boolean; // Indicates if the schema is active + auditDetails: AuditDetails; // Audit metadata for the schema definition +} + +/** + * Detailed structure of a schema definition + */ +interface Definition { + type: string; // Type of schema (e.g., object, array) + title?: string; // Optional title of the schema + $schema: string; // URI of the schema + required: string[]; // Array of required fields + "x-unique": string[]; // Array of unique constraints + properties?: any; // Properties within the schema + "x-ref-schema"?: XRefSchema[]; // Array of cross-references to other schemas + description?: string; // Optional description of the schema + additionalProperties?: boolean; // Indicates if additional properties are allowed + unique?: string[]; // Array of fields that must be unique +} + +/** + * Cross-reference schema for related fields + */ +interface XRefSchema { + fieldPath: string; // Path to the field within the schema + schemaCode: string; // Code of the schema that is referenced +} + +/** + * Criteria for requesting MDMS schema definitions + */ +export interface MDMSSchemaRequestCriteria { + SchemaDefCriteria: SchemaDefCriteria; // Criteria details for schema definition request +} + +/** + * Detailed criteria structure for schema definition requests + */ +interface SchemaDefCriteria { + tenantId: string; // Tenant identifier for the schema definition + limit: number; // Limit on the number of schema definitions to fetch + codes?: string[]; // Optional array of schema codes to retrieve +} + +/** + * Criteria for requesting MDMS schema definitions + */ +export interface MDMSv1RequestCriteria { + MdmsCriteria: MDMSv1Criteria; // Criteria details for schema definition request +} + +/** + * Criteria for requesting MDMS schema definitions + */ +export interface MDMSv2RequestCriteria { + MdmsCriteria: MDMSv2Criteria; // Criteria details for schema definition request +} diff --git a/health-services/project-factory/src/server/models/index.ts b/health-services/project-factory/src/server/models/index.ts new file mode 100644 index 00000000000..bd0e5462792 --- /dev/null +++ b/health-services/project-factory/src/server/models/index.ts @@ -0,0 +1,8 @@ +import * as MDMSModels from './MDMS'; +import * as BoundaryModels from './Boundary'; + + +export { + MDMSModels, + BoundaryModels +}; diff --git a/health-services/project-factory/src/server/service/campaignManageService.ts b/health-services/project-factory/src/server/service/campaignManageService.ts index 4b397e8b28f..bd9ce407221 100644 --- a/health-services/project-factory/src/server/service/campaignManageService.ts +++ b/health-services/project-factory/src/server/service/campaignManageService.ts @@ -1,7 +1,7 @@ import express from "express"; -import { processBasedOnAction, searchProjectCampaignResourcData } from "../utils/campaignUtils"; +import { processBasedOnAction, processFetchMicroPlan, searchProjectCampaignResourcData, updateCampaignAfterSearch } from "../utils/campaignUtils"; import { logger } from "../utils/logger"; -import { validateProjectCampaignRequest, validateSearchProcessTracksRequest, validateSearchProjectCampaignRequest } from "../validators/campaignValidators"; +import { validateMicroplanRequest, validateProjectCampaignRequest, validateSearchProcessTracksRequest } from "../validators/campaignValidators"; import { validateCampaignRequest } from "../validators/genericValidator"; import { createRelatedResouce } from "../api/genericApis"; import { enrichCampaign } from "../api/campaignApis"; @@ -9,8 +9,9 @@ import { getProcessDetails, modifyProcessDetails } from "../utils/processTrackUt async function createProjectTypeCampaignService(request: express.Request) { // Validate the request for creating a project type campaign + logger.info("VALIDATING:: for project type"); await validateProjectCampaignRequest(request, "create"); - logger.info("VALIDATED THE PROJECT TYPE CREATE REQUEST"); + logger.info("VALIDATED:: THE PROJECT TYPE CREATE REQUEST"); // Process the action based on the request type await processBasedOnAction(request, "create"); @@ -27,16 +28,14 @@ async function updateProjectTypeCampaignService(request: express.Request) { return request?.body?.CampaignDetails; } -async function searchProjectTypeCampaignService( - request: express.Request, +async function searchProjectTypeCampaignService(campaignDetails: any ) { - // Validate the search request for project type campaigns - await validateSearchProjectCampaignRequest(request); + // await validateSearchProjectCampaignRequest(request); logger.info("VALIDATED THE PROJECT TYPE SEARCH REQUEST"); // Search for project campaign resource data - await searchProjectCampaignResourcData(request); - const responseBody: any = { CampaignDetails: request?.body?.CampaignDetails, totalCount: request?.body?.totalCount } + const { responseData, totalCount } = await searchProjectCampaignResourcData(campaignDetails); + const responseBody: any = { CampaignDetails: responseData, totalCount: totalCount } return responseBody; }; @@ -69,11 +68,32 @@ async function searchProcessTracksService( return resultArray }; +async function retryProjectTypeCampaignService(request: express.Request) { + logger.info("RETRYING THE PROJECT TYPE CAMPAIGN"); + await validateProjectCampaignRequest(request, "retry"); + logger.info("VALIDATED THE PROJECT TYPE RETRY REQUEST"); + request.body.CampaignDetails.action = "draft"; + await processBasedOnAction(request, "update"); + return request?.body?.CampaignDetails; +} + +async function fetchFromMicroplanService(request: express.Request) { + logger.info("FETCHING DATA FROM MICROPLAN"); + await validateMicroplanRequest(request); + logger.info("UPDATE CAMPAIGN OBJECT") + await updateCampaignAfterSearch(request, "MICROPLAN_FETCHING") + logger.info("Validated request successfully"); + processFetchMicroPlan(request); + return request.body.CampaignDetails; +} + export { createProjectTypeCampaignService, updateProjectTypeCampaignService, searchProjectTypeCampaignService, createCampaignService, - searchProcessTracksService + searchProcessTracksService, + retryProjectTypeCampaignService, + fetchFromMicroplanService } diff --git a/health-services/project-factory/src/server/service/dataManageService.ts b/health-services/project-factory/src/server/service/dataManageService.ts index f6ad7105f65..bf1f17b8355 100644 --- a/health-services/project-factory/src/server/service/dataManageService.ts +++ b/health-services/project-factory/src/server/service/dataManageService.ts @@ -1,8 +1,8 @@ import express from "express"; import { processGenericRequest } from "../api/campaignApis"; import { createAndUploadFile, getBoundarySheetData } from "../api/genericApis"; -import { getLocalizedName, processDataSearchRequest } from "../utils/campaignUtils"; -import { addDataToSheet, enrichResourceDetails, getLocalizedMessagesHandler, searchGeneratedResources, processGenerate, throwError } from "../utils/genericUtils"; +import { getLocalizedName, getResourceDetails, processDataSearchRequest } from "../utils/campaignUtils"; +import { addDataToSheet, enrichResourceDetails, getLocalizedMessagesHandler, searchGeneratedResources, processGenerate, replicateRequest } from "../utils/genericUtils"; import { getFormattedStringForDebug, logger } from "../utils/logger"; import { validateCreateRequest, validateDownloadRequest, validateSearchRequest } from "../validators/campaignValidators"; import { validateGenerateRequest } from "../validators/genericValidator"; @@ -11,6 +11,8 @@ import { getBoundaryTabName } from "../utils/boundaryUtils"; import { getNewExcelWorkbook } from "../utils/excelUtils"; import { redis, checkRedisConnection } from "../utils/redisUtils"; // Importing checkRedisConnection function import config from '../config/index' +import { callGenerate } from "../utils/generateUtils"; +import { generatedResourceStatuses } from "../config/constants"; @@ -31,12 +33,43 @@ const downloadDataService = async (request: express.Request) => { const type = request.query.type; // Get response data from the database const responseData = await searchGeneratedResources(request); + const resourceDetails = await getResourceDetails(request); + // Check if response data is available - if (!responseData || responseData.length === 0 && !request?.query?.id) { - logger.error("No data of type " + type + " with status Completed or with given id presnt in db ") + if ( + !responseData || + (responseData.length === 0 && !request?.query?.id) || + responseData?.[0]?.status === generatedResourceStatuses.failed + ) { + logger.error(`No data of type '${type}' with status 'Completed' or the provided ID is present in the database.`) // Throw error if data is not found - throwError("CAMPAIGN", 500, "GENERATION_REQUIRE"); + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo + }; + const params = { + type: request?.query?.type, + tenantId: request?.query?.tenantId, + forceUpdate: 'true', + hierarchyType: request?.query?.hierarchyType, + campaignId: request?.query?.campaignId, + }; + const newRequestToGenerate = replicateRequest(request, newRequestBody, params); + // Added auto generate since no previous generate request found + logger.info(`Triggering auto generate since no resources got generated for the given Campaign Id ${request?.query?.campaignId} & type ${request?.query?.type} `) + callGenerate(newRequestToGenerate, request?.query?.type); + + // throwError("CAMPAIGN", 500, "GENERATION_REQUIRE"); + } + + // Send response with resource details + if (resourceDetails != null && responseData != null && responseData.length > 0) { + responseData[0].additionalDetails = { + ...(responseData[0].additionalDetails || {}), + ...(resourceDetails?.additionalDetails || {}) + }; } + + return responseData; } @@ -66,14 +99,14 @@ const getBoundaryDataService = async ( logger.info("NO CACHE FOUND :: REQUEST :: " + cacheKey); } const workbook = getNewExcelWorkbook(); - const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); + const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType), true); const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); - const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; + const localizationMap = { ...(localizationMapHierarchy || {}), ...localizationMapModule }; // Retrieve boundary sheet data const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - addDataToSheet(boundarySheet, boundarySheetData); + addDataToSheet(request, boundarySheet, boundarySheetData, '93C47D', 40, true); const boundaryFileDetails: any = await createAndUploadFile(workbook, request); // Return boundary file details logger.info("RETURNS THE BOUNDARY RESPONSE"); @@ -92,7 +125,10 @@ const getBoundaryDataService = async ( const createDataService = async (request: any) => { - const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + const hierarchyType = request?.body?.ResourceDetails?.hierarchyType; + const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId, getLocalisationModuleName(hierarchyType), true); + const localizationMapModule = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + const localizationMap = { ...(localizationMapHierarchy || {}), ...localizationMapModule }; // Validate the create request logger.info("Validating data create request") await validateCreateRequest(request, localizationMap); @@ -122,4 +158,4 @@ export { getBoundaryDataService, createDataService, searchDataService -} \ No newline at end of file +} diff --git a/health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts b/health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts new file mode 100644 index 00000000000..568657d168d --- /dev/null +++ b/health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts @@ -0,0 +1,44 @@ +import config from "../config/index"; +import { httpRequest } from "./request"; +import { processBoundary } from "./campaignUtils"; + +async function consolidateBoundaries(messageObject: any, hierarchyType: any, tenantId: any, code: any, boundaries: any) { + const params = { + tenantId: tenantId, + codes: code, + hierarchyType: hierarchyType, + includeChildren: true, + }; + const header = { + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId + }${params.codes || ""}${params?.includeChildren || ""}`, + }; + const boundaryResponse = await httpRequest( + config.host.boundaryHost + config.paths.boundaryRelationship, + messageObject?.RequestInfo, + params, + undefined, + undefined, + header + ); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + const boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { + acc[boundary.code] = boundary?.includeAllChildren; + return acc; + }, {}); + const boundaryCodes = new Set( + boundaries.map((boundary: any) => boundary.code) + ); + await processBoundary( + boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], + boundaries, + boundaryChildren[ + boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]?.code + ], + boundaryCodes, + boundaryChildren + ); + return boundaries; + } +} +export { consolidateBoundaries, } \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/boundaryUtils.ts b/health-services/project-factory/src/server/utils/boundaryUtils.ts index 40aa4f437ed..9b6e0396d19 100644 --- a/health-services/project-factory/src/server/utils/boundaryUtils.ts +++ b/health-services/project-factory/src/server/utils/boundaryUtils.ts @@ -1,4 +1,6 @@ import config from "../config/index"; +import { logger } from "./logger"; +import { httpRequest } from "./request"; @@ -13,3 +15,54 @@ export const getBoundaryTabName = () => { return config?.boundary?.boundaryTab; }; + +export async function getLatLongMapForBoundaryCodes(request:any, boundaryCodeList: any[]) { + const chunkSize = 20; + const boundaryCodeChunks = []; + let boundaryCodeLatLongMap: { [key: string]: number[] } = {}; // Map to hold lat/long data for boundary codes + + // Split the boundaryCodeList into chunks of 20 + for (let i = 0; i < boundaryCodeList.length; i += chunkSize) { + boundaryCodeChunks.push(boundaryCodeList.slice(i, i + chunkSize)); + } + + // Process each chunk + for (const chunk of boundaryCodeChunks) { + const boundaryCodeString = chunk.join(", "); + + // Only proceed if there are valid boundary codes + if (boundaryCodeList.length > 0 && boundaryCodeString) { + logger.info(`Creating boundary entities for codes: ${boundaryCodeString}`); + + try { + // Make the API request to fetch boundary entities + const boundaryEntityResponse = await httpRequest( + config.host.boundaryHost + config.paths.boundaryEntity, + request.body, // Passing the request body + { tenantId: request?.query?.tenantId, codes: boundaryCodeString } // Query params + ); + + // Process the boundary entities and extract lat/long for 'Point' geometries + if (boundaryEntityResponse?.Boundary) { + for (const boundary of boundaryEntityResponse.Boundary) { + if (boundary?.geometry && boundary.geometry.type === "Point") { + boundaryCodeLatLongMap[boundary.code] = boundary.geometry.coordinates; + } + } + } + + } catch (error: any) { + // Log error but do not stop the process for other chunks + console.log(error); + logger.error(`Failed to fetch boundary entities for codes: ${boundaryCodeString}, Error: ${error.message}`); + } + + } else { + // Log when the chunk is empty or invalid + logger.debug(`Skipping empty or invalid chunk: ${boundaryCodeString}`); + } + } + boundaryCodeLatLongMap['ADMIN_MO'] = [200,100]; + // Return or process the map further if needed + return boundaryCodeLatLongMap; +} diff --git a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts index f4698f4b77d..a6f1b821c00 100644 --- a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts @@ -1,15 +1,19 @@ import createAndSearch from "../config/createAndSearch"; import config from "../config"; -import { getDataFromSheet, getLocalizedMessagesHandlerViaRequestInfo, throwError } from "./genericUtils"; +import { getDataFromSheet, getLocalizedMessagesHandlerViaRequestInfo, replicateRequest, throwError } from "./genericUtils"; import { getFormattedStringForDebug, logger } from "./logger"; import { defaultheader, httpRequest } from "./request"; import { produceModifiedMessages } from "../kafka/Producer"; import { enrichAndPersistCampaignWithError, getLocalizedName } from "./campaignUtils"; import { campaignStatuses, resourceDataStatuses } from "../config/constants"; -import { createCampaignService } from "../service/campaignManageService"; +import { createCampaignService, searchProjectTypeCampaignService } from "../service/campaignManageService"; import { persistTrack } from "./processTrackUtils"; import { processTrackTypes, processTrackStatuses } from "../config/constants"; -import { createProjectFacilityHelper, createProjectResourceHelper, createStaffHelper } from "../api/genericApis"; +import { createProjectFacilityHelper, createProjectResourceHelper, createProjectStaffHelper } from "../api/genericApis"; +import { buildSearchCriteria, delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary, processResources } from "./onGoingCampaignUpdateUtils"; +import { searchDataService } from "../service/dataManageService"; +import { getHierarchy } from "../api/campaignApis"; +import { consolidateBoundaries } from "./boundariesConsolidationUtils"; async function createBoundaryWithProjectMapping(projects: any, boundaryWithProject: any) { @@ -23,19 +27,22 @@ async function createBoundaryWithProjectMapping(projects: any, boundaryWithProje } } -function getPvarIds(messageObject: any) { +export function getPvarIds(messageObject: any) { + //update to set now + logger.info("campaign product resource mapping started"); const deliveryRules = messageObject?.CampaignDetails?.deliveryRules; const uniquePvarIds = new Set(); // Create a Set to store unique pvar IDs if (deliveryRules) { for (const deliveryRule of deliveryRules) { - const products = deliveryRule?.products; + const products = deliveryRule?.resources; if (products) { for (const product of products) { - uniquePvarIds.add(product?.value); // Add pvar ID to the Set + uniquePvarIds.add(product?.productVariantId); // Add pvar ID to the Set } } } } + logger.info(`campaign product resource found items : ${JSON.stringify(uniquePvarIds)}`); return Array.from(uniquePvarIds); // Convert Set to array before returning } @@ -107,7 +114,11 @@ function findCommonParent(codes: string[], root: any) { function mapBoundaryCodes(resource: any, code: string, boundaryCode: string, boundaryCodes: any, allBoundaries: any) { // Split boundary codes if they have comma separated values - const boundaryCodesArray = boundaryCode.split(',').map((bc: string) => bc.trim()); + const boundaryCodesArray = boundaryCode + ? boundaryCode.includes(',') + ? boundaryCode.split(',').map((bc: string) => bc.trim()).filter(Boolean) + : [boundaryCode.trim()] + : []; if (resource?.type == "user" && boundaryCodesArray?.length > 1 && config.user.mapUserViaCommonParent) { const commonParent = findCommonParent(boundaryCodesArray, allBoundaries); if (commonParent) { @@ -137,26 +148,128 @@ function mapBoundaryCodes(resource: any, code: string, boundaryCode: string, bou } } + +function splitBoundaryCodes(boundaryCode: string) { + return boundaryCode.includes(',') + ? boundaryCode.split(',').map((code: string) => code.trim()).filter(Boolean) + : [boundaryCode.trim()].filter(Boolean); +} + + +async function fetchActiveIdentifiersFromParentCampaign( + resource: any, + resourcesFromParentCampaign: any[], + messageObject: any, + sheetName: any, + localizationMap: any, + activeColumn: string, + uniqueCodeColumn: string +): Promise { + let activeUniqueIdentifiersFromParent: any[] = []; + + if (messageObject?.parentCampaign) { + const matchingParentResource = resourcesFromParentCampaign.find( + (parentResource: any) => parentResource.type === resource.type + ); + + if (matchingParentResource) { + const parentCreateResourceId = matchingParentResource.createResourceId || ''; + const searchCriteria = buildSearchCriteria(messageObject, [parentCreateResourceId], matchingParentResource?.type); + const responseFromDataSearch = await searchDataService(replicateRequest(messageObject, searchCriteria)); + + const parentProcessedFileStoreId = responseFromDataSearch?.[0]?.processedFilestoreId; + + const parentResourceData: any = await getDataFromSheet( + messageObject, + parentProcessedFileStoreId, + messageObject?.Campaign?.tenantId, + undefined, + sheetName[matchingParentResource?.type], + localizationMap + ); + + activeUniqueIdentifiersFromParent = parentResourceData + .filter((row: any) => row[activeColumn] === "Active") + .map((row: any) => row[uniqueCodeColumn]); + } + } + + return activeUniqueIdentifiersFromParent; +} + + async function enrichBoundaryCodes(resources: any[], messageObject: any, boundaryCodes: any, sheetName: any) { const localizationMap: any = messageObject?.localizationMap const allBoundaries = await getAllBoundaries(messageObject, messageObject?.Campaign?.tenantId, messageObject?.Campaign?.boundaryCode, messageObject?.Campaign?.hierarchyType); + const delinkOperations: any = []; + const linkOperations: any = []; + const resourcesFromParentCampaign = messageObject?.parentCampaign?.resources || []; for (const resource of resources) { + const uniqueCodeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.uniqueIdentifierColumnName, localizationMap) + let activeColumn: any; + if (createAndSearch?.[resource?.type]?.activeColumn && createAndSearch?.[resource?.type]?.activeColumnName) { + activeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.activeColumnName, localizationMap); + } const processedFilestoreId = resource?.processedFilestoreId; + const activeUniqueIdentifiersFromParent = await fetchActiveIdentifiersFromParentCampaign( + resource, + resourcesFromParentCampaign, + messageObject, + sheetName, + localizationMap, + activeColumn, + uniqueCodeColumn + ); if (processedFilestoreId) { const dataFromSheet: any = await getDataFromSheet(messageObject, processedFilestoreId, messageObject?.Campaign?.tenantId, undefined, sheetName[resource?.type], localizationMap); for (const data of dataFromSheet) { - const uniqueCodeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.uniqueIdentifierColumnName, localizationMap) const code = data[uniqueCodeColumn]; if (code) { // Extract boundary codes const boundaryCode = data[getLocalizedName(createAndSearch?.[resource?.type]?.boundaryValidation?.column, localizationMap)]; - var active: any = "Active"; + let active: any = "Active"; if (createAndSearch?.[resource?.type]?.activeColumn && createAndSearch?.[resource?.type]?.activeColumnName) { - var activeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.activeColumnName, localizationMap); active = data[activeColumn]; } - if (boundaryCode && active == "Active") { - mapBoundaryCodes(resource, code, boundaryCode, boundaryCodes, allBoundaries); + if (boundaryCode && active === "Active") { + if (!messageObject?.parentCampaign) { + mapBoundaryCodes(resource, code, boundaryCode, boundaryCodes, allBoundaries); + } + else { + const existingBoundaryColumn = splitBoundaryCodes( + data[getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", localizationMap)] || "" + ); + + const newBoundaryColumn = splitBoundaryCodes(boundaryCode); + + existingBoundaryColumn.forEach((boundary: any) => { + if (!newBoundaryColumn.includes(boundary)) { + delinkOperations.push({ + resource, messageObject, boundary, code, isDelink: true + }); + } + }); + + // Collect link operations for new boundaries + newBoundaryColumn.forEach((boundary: any) => { + linkOperations.push({ + resource, messageObject, boundary, code, isDelink: false + }); + }); + } + } + else { + if (messageObject?.parentCampaign) { + if (boundaryCode && activeUniqueIdentifiersFromParent.includes(code) && active !== "Active") { + const boundariesToBeDelinked = splitBoundaryCodes(data[getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", localizationMap)] || ""); + boundariesToBeDelinked.forEach((boundary: any) => { + delinkOperations.push({ + resource, messageObject, boundary, code, isDelink: true + }); + }); + + } + } } } else { @@ -165,6 +278,41 @@ async function enrichBoundaryCodes(resources: any[], messageObject: any, boundar } } } + + // Process delink operations sequentially + for (const delinkData of delinkOperations) { + try { + const isMappingAlreadyPresent = await delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary( + delinkData.resource, + delinkData.messageObject, + delinkData.boundary, + delinkData.code, + delinkData.isDelink + ); + logger.info(`Delinking ${delinkData.boundary} from ${delinkData.code} resource`); + logger.info("Delink operation complete, mapping present:", isMappingAlreadyPresent); + } catch (err: any) { + logger.error(`Error during delink operation for ${delinkData.boundary}: ${err.message}`); + } + } + + // Process link operations sequentially + for (const linkData of linkOperations) { + try { + const isMappingAlreadyPresent = await delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary( + linkData.resource, + linkData.messageObject, + linkData.boundary, + linkData.code, + linkData.isDelink + ); + if (!isMappingAlreadyPresent) { + mapBoundaryCodes(linkData.resource, linkData.code, linkData.boundary, boundaryCodes, allBoundaries); + } + } catch (err: any) { + logger.error(`Error during link operation for ${linkData.boundary}: ${err.message}`); + } + } } @@ -190,6 +338,21 @@ async function enrichBoundaryWithProject(messageObject: any, boundaryWithProject logger.debug(`boundaryWise Project mapping : ${getFormattedStringForDebug(boundaryWithProject)}`); logger.info("boundaryCodes mapping : " + JSON.stringify(boundaryCodes)); } +function filterBoundariesByHierarchy(hierarchy: any, boundaries: any) { + // Iterate through the hierarchy in order + for (const level of hierarchy) { + // Find boundaries matching the current level type + const matchingBoundaries = boundaries.filter((boundary: any) => boundary.type === level); + + if (matchingBoundaries.length > 0) { + // If matches are found, return them + return matchingBoundaries; + } + } + + // If no matches are found, return an empty array + return []; +} async function getProjectMappingBody(messageObject: any, boundaryWithProject: any, boundaryCodes: any) { const Campaign: any = { @@ -197,16 +360,60 @@ async function getProjectMappingBody(messageObject: any, boundaryWithProject: an tenantId: messageObject?.Campaign?.tenantId, CampaignDetails: [] } + const newlyAddedBoundaryCodes = new Set(); // A set to store unique boundary codes + if (messageObject?.CampaignDetails?.parentId) { + const CampaignDetails = { + "ids": [messageObject?.CampaignDetails?.id], + "tenantId": messageObject?.CampaignDetails?.tenantId + } + const campaignSearchResponse = await searchProjectTypeCampaignService(CampaignDetails); + const boundaries = campaignSearchResponse?.CampaignDetails?.[0]?.boundaries; + const hierarchy = await getHierarchy(messageObject, messageObject?.CampaignDetails?.tenantId, messageObject?.CampaignDetails?.hierarchyType); + const boundariesWhichAreRootInThisFlow = filterBoundariesByHierarchy(hierarchy, boundaries); + for (const boundary of boundariesWhichAreRootInThisFlow) { + const boundaryCodesFetchedFromGivenRoot = await consolidateBoundaries( + messageObject, + messageObject?.CampaignDetails?.hierarchyType, + messageObject?.CampaignDetails?.tenantId, + boundary?.code, + boundaries + ); + // Add each boundary code to the set if it exists + if (boundaryCodesFetchedFromGivenRoot && + Array.isArray(boundaryCodesFetchedFromGivenRoot) && + boundaryCodesFetchedFromGivenRoot.length > 0) { + boundaryCodesFetchedFromGivenRoot + .filter((boundary: any) => boundary?.code) // Filter boundaries with valid codes + .forEach((boundary: any) => newlyAddedBoundaryCodes.add(boundary.code)); + } + } + } + + for (const key of Object.keys(boundaryWithProject)) { if (boundaryWithProject[key]) { const resources: any[] = []; - const pvarIds = getPvarIds(messageObject); - if (pvarIds && Array.isArray(pvarIds) && pvarIds.length > 0) { - resources.push({ - type: "resource", - resourceIds: pvarIds - }) + if (messageObject?.CampaignDetails?.parentId && newlyAddedBoundaryCodes.has(key)) { + logger.info("project resource mapping for newly created projects in update flow") + const pvarIds = getPvarIds(messageObject); + if (pvarIds && Array.isArray(pvarIds) && pvarIds.length > 0) { + resources.push({ + type: "resource", + resourceIds: pvarIds + }) + } } + + if (!messageObject?.CampaignDetails?.parentId) { + const pvarIds = getPvarIds(messageObject); + if (pvarIds && Array.isArray(pvarIds) && pvarIds.length > 0) { + resources.push({ + type: "resource", + resourceIds: pvarIds + }) + } + } + for (const type of Object.keys(boundaryCodes)) { if (boundaryCodes[type][key] && Array.isArray(boundaryCodes[type][key]) && boundaryCodes[type][key].length > 0) { resources.push({ @@ -218,13 +425,14 @@ async function getProjectMappingBody(messageObject: any, boundaryWithProject: an Campaign.CampaignDetails.push({ projectId: boundaryWithProject[key], resources: resources - }) + }); } } return { RequestInfo: messageObject?.RequestInfo, Campaign: Campaign, - CampaignDetails: messageObject?.CampaignDetails + CampaignDetails: messageObject?.CampaignDetails, + parentCampaign: messageObject?.parentCampaign } } @@ -354,18 +562,17 @@ export async function handleCampaignMapping(messageObject: any) { } } -export async function handleStaffMapping(mappingArray: any[], campaignId: string, messageObject: any) { +export async function handleStaffMapping(mappingArray: any[], campaignId: string, messageObject: any, type: string) { await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.inprogress); try { - const promises = [] - logger.debug("Array of staff mapping: " + getFormattedStringForDebug(mappingArray)); - for (const staffMapping of mappingArray) { - const { resource, projectId, resouceBody, tenantId, startDate, endDate } = staffMapping; - for (const resourceId of resource?.resourceIds) { - promises.push(createStaffHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)) - } - } - await Promise.all(promises); + logger.debug(`staff mapping count: ${mappingArray.length}`); + await processResourceOrFacilityOrUserMappingsInBatches(type, mappingArray, config?.batchSize || 100); + // for (const staffMapping of mappingArray) { + // const { resource, projectId, resouceBody, tenantId, startDate, endDate } = staffMapping; + // for (const resourceId of resource?.resourceIds) { + // promises.push(createStaffHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)) + // } + // } } catch (error: any) { logger.error("Error in staff mapping: " + error); await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); @@ -375,18 +582,63 @@ export async function handleStaffMapping(mappingArray: any[], campaignId: string await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.completed); } -export async function handleResourceMapping(mappingArray: any, campaignId: any, messageObject: any) { - await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.inprogress); - try { - const promises = [] - logger.debug("Arrray of resource mapping: " + getFormattedStringForDebug(mappingArray)); - for (const mapping of mappingArray) { - const { resource, projectId, resouceBody, tenantId, startDate, endDate } = mapping; - for (const resourceId of resource?.resourceIds) { - promises.push(createProjectResourceHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)); +async function processResourceOrFacilityOrUserMappingsInBatches(type: string, mappingArray: any, batchSize: number) { + logger.info("Processing resource mappings in batches..."); + let promises: Promise[] = []; + let totalCreated = 0; // To keep track of the total number of created resources + let batchCount = 0; // To log batch-wise progress + // Determine the helper function to use based on the type + let createHelperFn: any; + if (type === 'resource') { + createHelperFn = createProjectResourceHelper; + } else if (type === 'staff') { + createHelperFn = createProjectStaffHelper; + } else if (type === 'facility') { + createHelperFn = createProjectFacilityHelper; + } else { + logger.error(`Unsupported type: ${type}`); + return; // Exit the function if the type is unsupported + } + + for (const mapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId, startDate, endDate } = mapping; + + for (const resourceId of resource?.resourceIds || []) { + promises.push( + createHelperFn(resourceId, projectId, resouceBody, tenantId, startDate, endDate).then(() => { + totalCreated++; + }) + ); + + if (promises.length >= batchSize) { + batchCount++; + logger.info(`Processing batch ${batchCount} with ${promises.length} promises.`); + try { + await Promise.all(promises); // Wait for all promises in the current batch + } catch (error) { + logger.error(`Batch ${batchCount} failed:`, error); + throw error; // Ensure any error in the batch is propagated + } promises = []; // Reset the array for the next batch } } + } + + // Process any remaining promises + if (promises.length > 0) { + batchCount++; + logger.info(`Processing final batch ${batchCount} with ${promises.length} promises.`); await Promise.all(promises); + } + + logger.info(`Processing completed. Total resources created: ${totalCreated}`); +} + + +export async function handleResourceMapping(mappingArray: any[], campaignId: any, messageObject: any, type: string) { + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.inprogress); + try { + logger.debug(`Resource mapping count: ${mappingArray.length}`); + await processResourceOrFacilityOrUserMappingsInBatches(type, mappingArray, config?.batchSize || 100); } catch (error: any) { logger.error("Error in resource mapping: " + error); await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); @@ -396,18 +648,17 @@ export async function handleResourceMapping(mappingArray: any, campaignId: any, await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.completed); } -export async function handleFacilityMapping(mappingArray: any, campaignId: any, messageObject: any) { +export async function handleFacilityMapping(mappingArray: any, campaignId: any, messageObject: any, type: string) { await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.inprogress); try { - const promises = [] - logger.debug("Array of facility mapping: " + getFormattedStringForDebug(mappingArray)); - for (const mapping of mappingArray) { - const { resource, projectId, resouceBody, tenantId } = mapping; - for (const resourceId of resource?.resourceIds) { - promises.push(createProjectFacilityHelper(resourceId, projectId, resouceBody, tenantId)); - } - } - await Promise.all(promises); + logger.debug(`facility mapping count: ${mappingArray.length}`); + // for (const mapping of mappingArray) { + // const { resource, projectId, resouceBody, tenantId } = mapping; + // for (const resourceId of resource?.resourceIds) { + // promises.push(createProjectFacilityHelper(resourceId, projectId, resouceBody, tenantId)); + // } + // } + await processResourceOrFacilityOrUserMappingsInBatches(type, mappingArray, config?.batchSize || 100); } catch (error: any) { logger.error("Error in facility mapping: " + error); await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); @@ -423,12 +674,19 @@ export async function processMapping(mappingObject: any) { const resourceMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "resource"); const facilityMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "facility"); const staffMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "staff"); - await handleResourceMapping(resourceMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); - await handleFacilityMapping(facilityMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); - await handleStaffMapping(staffMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); + await handleResourceMapping(resourceMappingArray, mappingObject?.CampaignDetails?.id, mappingObject, "resource"); + await handleFacilityMapping(facilityMappingArray, mappingObject?.CampaignDetails?.id, mappingObject, "facility"); + await handleStaffMapping(staffMappingArray, mappingObject?.CampaignDetails?.id, mappingObject, "staff"); } logger.info("Mapping completed successfully for campaign: " + mappingObject?.CampaignDetails?.id); mappingObject.CampaignDetails.status = campaignStatuses.inprogress + if (mappingObject?.parentCampaign) { + await processResources(mappingObject); + mappingObject.CampaignDetails.campaignDetails.boundaries = [ + ...mappingObject.CampaignDetails.campaignDetails.boundaries, + ...mappingObject.parentCampaign.boundaries + ]; + } const produceMessage: any = { CampaignDetails: mappingObject?.CampaignDetails } diff --git a/health-services/project-factory/src/server/utils/campaignUtils.ts b/health-services/project-factory/src/server/utils/campaignUtils.ts index 1fbf424ecf9..57a257d8092 100644 --- a/health-services/project-factory/src/server/utils/campaignUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignUtils.ts @@ -1,1892 +1,3799 @@ - import { defaultheader, httpRequest } from "./request"; import config from "../config/index"; -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4 } from "uuid"; import { produceModifiedMessages } from "../kafka/Producer"; -import { confirmProjectParentCreation, createProjectCampaignResourcData, getCampaignSearchResponse, getHierarchy, handleResouceDetailsError, projectCreate } from "../api/campaignApis"; -import { getCampaignNumber, createAndUploadFile, getSheetData, createExcelSheet, getAutoGeneratedBoundaryCodesHandler, createBoundaryEntities, createBoundaryRelationship, getMDMSV1Data, getTargetSheetDataAfterCode, callMdmsTypeSchema, getSheetDataFromWorksheet } from "../api/genericApis"; +import { + confirmProjectParentCreation, + createProjectCampaignResourcData, + getCampaignSearchResponse, + getHierarchy, + handleResouceDetailsError, + projectCreate, + projectUpdateForTargets, +} from "../api/campaignApis"; +import { + getCampaignNumber, + createAndUploadFile, + createExcelSheet, + getAutoGeneratedBoundaryCodesHandler, + createBoundaryEntities, + getMDMSV1Data, + getTargetSheetDataAfterCode, + callMdmsTypeSchema, + getSheetDataFromWorksheet, + getTargetWorkbook, + createAndUploadJsonFile, + createBoundaryRelationship, + getSheetData, +} from "../api/genericApis"; import { getFormattedStringForDebug, logger } from "./logger"; import createAndSearch from "../config/createAndSearch"; -import { addDataToSheet, createBoundaryDataMainSheet, createReadMeSheet, findMapValue, getBoundaryRelationshipData, getConfigurableColumnHeadersFromSchemaForTargetSheet, getLocalizedHeaders, getLocalizedMessagesHandler, getMdmsDataBasedOnCampaignType, modifyBoundaryData, replicateRequest, throwError } from "./genericUtils"; +import { + addDataToSheet, + createBoundaryDataMainSheet, + createReadMeSheet, + findMapValue, + getBoundaryRelationshipData, + getConfigurableColumnHeadersFromSchemaForTargetSheet, + getLocalizedHeaders, + getLocalizedMessagesHandler, + getMdmsDataBasedOnCampaignType, + modifyBoundaryData, + replicateRequest, + throwError, +} from "./genericUtils"; import { enrichProjectDetailsFromCampaignDetails } from "./transforms/projectTypeUtils"; import { executeQuery } from "./db"; -import { campaignDetailsTransformer, genericResourceTransformer } from "./transforms/searchResponseConstructor"; +import { + campaignDetailsTransformer, + genericResourceTransformer, +} from "./transforms/searchResponseConstructor"; import { transformAndCreateLocalisation } from "./transforms/localisationMessageConstructor"; -import { campaignStatuses, headingMapping, processTrackStatuses, processTrackTypes, resourceDataStatuses } from "../config/constants"; -import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; -import { searchProjectTypeCampaignService } from "../service/campaignManageService"; -import { validateBoundaryOfResouces } from "../validators/campaignValidators"; -import { getExcelWorkbookFromFileURL, getNewExcelWorkbook, lockTargetFields, updateFontNameToRoboto } from "./excelUtils"; -import { areBoundariesSame, callGenerateIfBoundariesDiffer } from "./generateUtils"; +import { + campaignStatuses, + headingMapping, + processTrackStatuses, + processTrackTypes, + resourceDataStatuses, +} from "../config/constants"; +import { getBoundaryTabName } from "./boundaryUtils"; +import { + searchProjectTypeCampaignService, + updateProjectTypeCampaignService, +} from "../service/campaignManageService"; +import { + validateBoundaryOfResouces, + validateBoundarySheetDataInCreateFlow, +} from "../validators/campaignValidators"; +import { + getExcelWorkbookFromFileURL, + getNewExcelWorkbook, + lockTargetFields, + updateFontNameToRoboto, +} from "./excelUtils"; +import { + areBoundariesSame, + callGenerate, + callGenerateIfBoundariesOrCampaignTypeDiffer, +} from "./generateUtils"; import { createProcessTracks, persistTrack } from "./processTrackUtils"; -import { generateDynamicTargetHeaders, isDynamicTargetTemplateForProjectType, updateTargetColumnsIfDeliveryConditionsDifferForSMC } from "./targetUtils"; -const _ = require('lodash'); - - +import { + generateDynamicTargetHeaders, + isDynamicTargetTemplateForProjectType, + updateTargetColumnsIfDeliveryConditionsDifferForSMC, +} from "./targetUtils"; +import { + callGenerateWhenChildCampaigngetsCreated, + fetchProjectsWithBoundaryCodeAndReferenceId, + fetchProjectsWithProjectId, + getBoundariesFromCampaignSearchResponse, + getBoundaryProjectMappingFromParentCampaign, + getColumnIndexByHeader, + hideColumnsOfProcessedFile, + modifyNewSheetData, + unhideColumnsOfProcessedFile, +} from "./onGoingCampaignUpdateUtils"; +import { changeCreateDataForMicroplan, lockSheet } from "./microplanUtils"; +const _ = require("lodash"); +import { searchDataService } from "../service/dataManageService"; +import { searchMDMSDataViaV2Api } from "../api/coreApis"; +import { deleteRedisCacheKeysWithPrefix } from "./redisUtils"; +import { + fetchFacilityData, + fetchTargetData, + fetchUserData, +} from "./microplanIntergration"; function updateRange(range: any, worksheet: any) { - let maxColumnIndex = 0; - - // Iterate through each row to find the last column with data - for (let row = range.s.r; row <= range.e.r; row++) { - const rowCells = worksheet.getRow(row + 1); // ExcelJS rows are 1-based - rowCells.eachCell((cell: any, colNumber: number) => { - if (cell.value !== undefined && colNumber > maxColumnIndex) { - maxColumnIndex = colNumber; - } - }); - } + let maxColumnIndex = 0; + + // Iterate through each row to find the last column with data + for (let row = range.s.r; row <= range.e.r; row++) { + const rowCells = worksheet.getRow(row + 1); // ExcelJS rows are 1-based + rowCells.eachCell((cell: any, colNumber: number) => { + if (cell.value !== undefined && colNumber > maxColumnIndex) { + maxColumnIndex = colNumber; + } + }); + } - // Update the end column of the range with the maximum column index found - range.e.c = maxColumnIndex; + // Update the end column of the range with the maximum column index found + range.e.c = maxColumnIndex; } function findAndChangeColumns(worksheet: any, columns: any) { - const firstRow = worksheet.getRow(1); // First row (ExcelJS is 1-based) - firstRow.eachCell((cell: any, colNumber: number) => { - if (cell.value === '#status#') { - columns.statusColumn = cell.address.replace(/\d+/g, ''); - // Set the cell color to green - cell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'CCCC00' } - }; - // Delete status column cells in subsequent rows - worksheet.eachRow((row: any, rowIndex: number) => { - if (rowIndex > 1) { - const statusCell = row.getCell(colNumber); - statusCell.value = undefined; - } - }); + const firstRow = worksheet.getRow(1); + firstRow.eachCell((cell: any, colNumber: number) => { + if (cell.value === "#status#") { + columns.statusColumn = cell.address.replace(/\d+/g, ""); + // Set the cell color to green + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + // Delete status column cells in subsequent rows + worksheet.eachRow((row: any, rowIndex: number) => { + if (rowIndex > 1) { + const statusCell = row.getCell(colNumber); + statusCell.value = undefined; } - if (cell.value === '#errorDetails#') { - columns.errorDetailsColumn = cell.address.replace(/\d+/g, ''); - // Set the cell color to green - cell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'CCCC00' } - }; - // Delete error details column cells in subsequent rows - worksheet.eachRow((row: any, rowIndex: number) => { - if (rowIndex > 1) { - const errorDetailsCell = row.getCell(colNumber); - errorDetailsCell.value = undefined; - } - }); + }); + } + if (cell.value === "#errorDetails#") { + columns.errorDetailsColumn = cell.address.replace(/\d+/g, ""); + // Set the cell color to green + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + // Delete error details column cells in subsequent rows + worksheet.eachRow((row: any, rowIndex: number) => { + if (rowIndex > 1) { + const errorDetailsCell = row.getCell(colNumber); + errorDetailsCell.value = undefined; } - }); + }); + } + }); } function makeColumns(worksheet: any, range: any, columns: any) { - // If the status column doesn't exist, calculate the next available column - if (!columns?.statusColumn) { - const emptyColumnIndex = range.e.c; - columns.statusColumn = String.fromCharCode(65 + (emptyColumnIndex + 1)); - const statusCell = worksheet.getCell(`${columns.statusColumn}1`); - statusCell.value = '#status#'; - statusCell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'CCCC00' } - }; - statusCell.font = { bold: true }; - } - - // Calculate errorDetails column one column to the right of status column - if (!columns?.errorDetailsColumn) { - columns.errorDetailsColumn = String.fromCharCode(columns?.statusColumn.charCodeAt(0) + 1); - const errorDetailsCell = worksheet.getCell(`${columns.errorDetailsColumn}1`); - errorDetailsCell.value = '#errorDetails#'; - errorDetailsCell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'CCCC00' } - }; - errorDetailsCell.font = { bold: true }; - } + // If the status column doesn't exist, calculate the next available column + if (!columns?.statusColumn) { + const emptyColumnIndex = range.e.c; + columns.statusColumn = String.fromCharCode(65 + (emptyColumnIndex + 1)); + const statusCell = worksheet.getCell(`${columns.statusColumn}1`); + statusCell.value = "#status#"; + statusCell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + statusCell.font = { bold: true }; + worksheet.getColumn(columns.statusColumn).width = 40; + } + + // Calculate errorDetails column one column to the right of status column + if (!columns?.errorDetailsColumn) { + columns.errorDetailsColumn = String.fromCharCode( + columns?.statusColumn.charCodeAt(0) + 1 + ); + const errorDetailsCell = worksheet.getCell( + `${columns.errorDetailsColumn}1` + ); + errorDetailsCell.value = "#errorDetails#"; + errorDetailsCell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + errorDetailsCell.font = { bold: true }; + worksheet.getColumn(columns.errorDetailsColumn).width = 40; + } } - function findColumns(worksheet: any) { - const range = { - s: { r: 0, c: 0 }, - e: { r: worksheet.rowCount - 1, c: worksheet.columnCount - 1 } - }; - - // Check if the status column already exists in the first row - var columns = {} + const range = { + s: { r: 0, c: 0 }, + e: { r: worksheet.rowCount - 1, c: worksheet.columnCount - 1 }, + }; - findAndChangeColumns(worksheet, columns); + // Check if the status column already exists in the first row + var columns = {}; - makeColumns(worksheet, range, columns); + findAndChangeColumns(worksheet, columns); - updateRange(range, worksheet); - - return columns; -} + makeColumns(worksheet, range, columns); -function enrichErrors(errorData: any, worksheet: any, statusColumn: any, errorDetailsColumn: any, additionalDetailsErrors: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { - if (errorData) { - errorData.forEach((error: any) => { - const rowIndex = error.rowNumber; // ExcelJS rows are 1-based - const statusCell = worksheet.getCell(`${statusColumn}${rowIndex}`); - const errorDetailsCell = worksheet.getCell(`${errorDetailsColumn}${rowIndex}`); - statusCell.value = error.status; - errorDetailsCell.value = error.errorDetails; + updateRange(range, worksheet); - if ((error?.status) && !(error?.status === "CREATED" || error?.status === "VALID")) { - additionalDetailsErrors.push(error); - } - }); - if (errorData.some((error: any) => error?.status === "CREATED")) { - const uniqueIdentifierFirstRowCell = `${createAndSearchConfig?.uniqueIdentifierColumn}1`; - const columnName = getLocalizedName(createAndSearchConfig?.uniqueIdentifierColumnName, localizationMap); - const uniqueIdentifierCell = worksheet.getCell(uniqueIdentifierFirstRowCell); - uniqueIdentifierCell.value = columnName; - - // Set the cell color to green - uniqueIdentifierCell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'ff9248' } // Green color - }; - uniqueIdentifierCell.font = { bold: true }; - // Hide the unique identifier column - worksheet.getColumn(createAndSearchConfig?.uniqueIdentifierColumn).hidden = true; - } - errorData.forEach((error: any) => { - const rowIndex = error.rowNumber; - if (error.isUniqueIdentifier) { - const uniqueIdentifierCell = worksheet.getCell(`${createAndSearchConfig.uniqueIdentifierColumn}${rowIndex}`); - uniqueIdentifierCell.value = error.uniqueIdentifier; - if (createAndSearchConfig?.activeColumn) { - const activeCell = worksheet.getCell(`${createAndSearchConfig.activeColumn}${rowIndex}`); - activeCell.value = "Active"; - } - } - }); - } + return columns; } -function enrichActiveColumn(worksheet: any, createAndSearchConfig: any, request: any) { - if (createAndSearchConfig?.activeColumn && request?.body?.dataToCreate) { - const dataToCreate = request.body.dataToCreate; - for (const data of dataToCreate) { - const rowNumber = data['!row#number!']; - const activeCell = worksheet.getCell(`${createAndSearchConfig?.activeColumn}${rowNumber}`); - activeCell.value = "Active"; +function enrichErrors( + errorData: any, + worksheet: any, + statusColumn: any, + errorDetailsColumn: any, + additionalDetailsErrors: any, + createAndSearchConfig: any, + localizationMap?: { [key: string]: string } +) { + if (errorData) { + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; // ExcelJS rows are 1-based + const statusCell = worksheet.getCell(`${statusColumn}${rowIndex}`); + const errorDetailsCell = worksheet.getCell( + `${errorDetailsColumn}${rowIndex}` + ); + statusCell.value = error.status; + errorDetailsCell.value = error.errorDetails; + + if ( + error?.status && + !(error?.status === "CREATED" || error?.status === "VALID") + ) { + additionalDetailsErrors.push(error); + } + }); + if (errorData.some((error: any) => error?.status === "CREATED")) { + const uniqueIdentifierFirstRowCell = `${createAndSearchConfig?.uniqueIdentifierColumn}1`; + const columnName = getLocalizedName( + createAndSearchConfig?.uniqueIdentifierColumnName, + localizationMap + ); + const uniqueIdentifierCell = worksheet.getCell( + uniqueIdentifierFirstRowCell + ); + uniqueIdentifierCell.value = columnName; + + // Set the cell color to green + uniqueIdentifierCell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "ff9248" }, // Green color + }; + uniqueIdentifierCell.font = { bold: true }; + // Hide the unique identifier column + worksheet.getColumn( + createAndSearchConfig?.uniqueIdentifierColumn + ).hidden = true; + } + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; + if (error.isUniqueIdentifier) { + const uniqueIdentifierCell = worksheet.getCell( + `${createAndSearchConfig.uniqueIdentifierColumn}${rowIndex}` + ); + uniqueIdentifierCell.value = error.uniqueIdentifier; + if (createAndSearchConfig?.activeColumn) { + const activeCell = worksheet.getCell( + `${createAndSearchConfig.activeColumn}${rowIndex}` + ); + activeCell.value = "Active"; } - } -} - -function deterMineLastColumnAndEnrichUserDetails(worksheet: any, errorDetailsColumn: any, userNameAndPassword: any, request: any, createAndSearchConfig: any) { - let lastColumn = errorDetailsColumn; - if (createAndSearchConfig?.uniqueIdentifierColumn !== undefined) { - lastColumn = createAndSearchConfig?.uniqueIdentifierColumn > errorDetailsColumn ? - createAndSearchConfig?.uniqueIdentifierColumn : - errorDetailsColumn; - } - - if (userNameAndPassword) { - worksheet.getCell("I1").value = "UserName"; - worksheet.getCell("J1").value = "Password"; - - // Set the fill color to green for cell I1 - worksheet.getCell("I1").fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'ff9248' } // Green color - }; - worksheet.getCell("I1").font = { bold: true }; - - // Set the fill color to green for cell J1 - worksheet.getCell("J1").fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'ff9248' } // Green color - }; - worksheet.getCell("J1").font = { bold: true }; - - userNameAndPassword.forEach((data: any) => { - const rowIndex = data.rowNumber; - worksheet.getCell(`I${rowIndex}`).value = data?.userName; - worksheet.getCell(`J${rowIndex}`).value = data?.password; - }); - - lastColumn = "J"; - request.body.userNameAndPassword = undefined; - } - - return lastColumn; + } + }); + } } -function adjustRef(worksheet: any, lastColumn: any) { - const range = getSheetDataFromWorksheet(worksheet).filter((row: any) => row).length; // Get the number of used rows - worksheet.views = [ - { state: 'frozen', ySplit: 1, topLeftCell: 'A2', activeCell: 'A2' } - ]; - worksheet.autoFilter = { - from: { - row: 1, - column: 1 - }, - to: { - row: range, - column: worksheet.getColumn(lastColumn).number - } +function enrichActiveAndUUidColumn( + worksheet: any, + createAndSearchConfig: any, + request: any +) { + if ( + createAndSearchConfig?.activeColumn && + request?.body?.dataToCreate && + request?.body?.dataToCreate?.length > 0 && + request?.body?.ResourceDetails?.type == "user" + ) { + const dataToCreate = request.body.dataToCreate; + for (const data of dataToCreate) { + const rowNumber = data["!row#number!"]; + const activeCell = worksheet.getCell( + `${createAndSearchConfig?.activeColumn}${rowNumber}` + ); + const uniqueIdentifierCell = worksheet.getCell( + `${createAndSearchConfig?.uniqueIdentifierColumn}${rowNumber}` + ); + activeCell.value = "Active"; + uniqueIdentifierCell.value = data["userServiceUuid"]; + } + } +} + +function deterMineLastColumnAndEnrichUserDetails( + worksheet: any, + errorDetailsColumn: number, + userNameAndPassword: + | { rowNumber: number; userName: string; password: string }[] + | undefined, + request: any, + createAndSearchConfig: { uniqueIdentifierColumn?: number } +): string { + // Determine the last column + let lastColumn: any = errorDetailsColumn; + if (createAndSearchConfig?.uniqueIdentifierColumn !== undefined) { + lastColumn = + createAndSearchConfig?.uniqueIdentifierColumn > errorDetailsColumn + ? createAndSearchConfig?.uniqueIdentifierColumn + : errorDetailsColumn; + } + + // Default columns + let usernameColumn = "J"; + let passwordColumn = "K"; + + // Update columns if the request indicates a different source + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ) { + usernameColumn = "F"; + passwordColumn = "G"; + } + + // Populate username and password columns if data is provided + if (userNameAndPassword) { + // Set headers with formatting + const setCellHeader = (cell: string) => { + worksheet.getCell(cell).value = + cell === usernameColumn + "1" ? "UserName" : "Password"; + worksheet.getCell(cell).fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "ff9248" }, // Green color + }; + worksheet.getCell(cell).font = { bold: true }; + const columnLetter = cell.replace(/\d+$/, ""); + worksheet.getColumn(columnLetter).width = 40; }; -} - -function processErrorData(request: any, createAndSearchConfig: any, workbook: any, sheetName: any, localizationMap?: { [key: string]: string }) { - const worksheet = workbook.getWorksheet(sheetName); - const errorData = request.body.sheetErrorDetails; - const userNameAndPassword = request.body.userNameAndPassword; - const columns: any = findColumns(worksheet); - const statusColumn = columns.statusColumn; - const errorDetailsColumn = columns.errorDetailsColumn; - const additionalDetailsErrors: any[] = []; - - enrichErrors(errorData, worksheet, statusColumn, errorDetailsColumn, additionalDetailsErrors, createAndSearchConfig, localizationMap); - enrichActiveColumn(worksheet, createAndSearchConfig, request); - - request.body.additionalDetailsErrors = additionalDetailsErrors; - - // Determine the last column to set the worksheet ref - const lastColumn = deterMineLastColumnAndEnrichUserDetails(worksheet, errorDetailsColumn, userNameAndPassword, request, createAndSearchConfig); - - // Adjust the worksheet ref to include the last column - adjustRef(worksheet, lastColumn); - updateFontNameToRoboto(worksheet) - - workbook.xlsx.writeBuffer(); -} - - -function processErrorDataForTargets(request: any, createAndSearchConfig: any, workbook: any, sheetName: any) { - const desiredSheet = workbook.getWorksheet(sheetName); - const columns: any = findColumns(desiredSheet); - const statusColumn = columns.statusColumn; - const errorDetailsColumn = columns.errorDetailsColumn; - - const errorData = request.body.sheetErrorDetails.filter((error: any) => error.sheetName === sheetName); - const additionalDetailsErrors: any = []; - - if (errorData) { - errorData.forEach((error: any) => { - const rowIndex = error.rowNumber; - if (error.isUniqueIdentifier) { - const uniqueIdentifierCell = createAndSearchConfig.uniqueIdentifierColumn + (rowIndex); - desiredSheet.getCell(uniqueIdentifierCell).value = error.uniqueIdentifier; - } - - const statusCell = statusColumn + (rowIndex); - const errorDetailsCell = errorDetailsColumn + (rowIndex); - desiredSheet.getCell(statusCell).value = error.status; - desiredSheet.getCell(errorDetailsCell).value = error.errorDetails; - - if (!(error.status === "CREATED" || error.status === "VALID")) { - additionalDetailsErrors.push(error); - } - }); - } - request.body.additionalDetailsErrors = additionalDetailsErrors; - updateFontNameToRoboto(desiredSheet) - workbook.worksheets[sheetName] = desiredSheet; -} - -async function updateStatusFile(request: any, localizationMap?: { [key: string]: string }) { - const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; - const tenantId = request?.body?.ResourceDetails?.tenantId; - const createAndSearchConfig = createAndSearch[request?.body?.ResourceDetails?.type]; - const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); + setCellHeader(usernameColumn + "1"); + setCellHeader(passwordColumn + "1"); - if (!fileResponse?.fileStoreIds?.[0]?.url) { - throwError("FILE", 500, "INVALID_FILE"); - } - const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; - const sheetName = createAndSearchConfig?.parseArrayConfig?.sheetName; - const localizedSheetName = getLocalizedName(sheetName, localizationMap); - const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, localizedSheetName); - const worksheet: any = workbook.getWorksheet(localizedSheetName); - processErrorData(request, createAndSearchConfig, workbook, localizedSheetName, localizationMap); - - // Set column widths - const columnWidths = Array(12).fill({ width: 30 }); - columnWidths.forEach((colWidth, index) => { - if (worksheet.getColumn(index + 1)) { - worksheet.getColumn(index + 1).width = colWidth.width; - } + // Set values + userNameAndPassword.forEach((data) => { + const rowIndex = data.rowNumber; + worksheet.getCell(`${usernameColumn}${rowIndex}`).value = data.userName; + worksheet.getCell(`${passwordColumn}${rowIndex}`).value = data.password; }); - const responseData = await createAndUploadFile(workbook, request); + // Update lastColumn based on the password column + lastColumn = passwordColumn; + } - logger.info('File updated successfully:' + JSON.stringify(responseData)); - if (responseData?.[0]?.fileStoreId) { - request.body.ResourceDetails.processedFileStoreId = responseData?.[0]?.fileStoreId; - } else { - throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); - } + return lastColumn; } -async function updateStatusFileForTargets(request: any, localizationMap?: { [key: string]: string }) { - const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; - const tenantId = request?.body?.ResourceDetails?.tenantId; - const createAndSearchConfig = createAndSearch[request?.body?.ResourceDetails?.type]; - const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); - - if (!fileResponse?.fileStoreIds?.[0]?.url) { - throwError("FILE", 500, "INVALID_FILE"); - } - - - const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; - - const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, ""); - - const sheetNames = workbook.worksheets.map((worksheet: any) => worksheet.name); - const localizedSheetNames = getLocalizedHeaders(sheetNames, localizationMap); - - localizedSheetNames.forEach((sheetName: any) => { - if (sheetName !== getLocalizedName(config?.boundary?.boundaryTab, localizationMap) && sheetName !== getLocalizedName(config.values.readMeTab, localizationMap)) { - processErrorDataForTargets(request, createAndSearchConfig, workbook, sheetName); - } - }); - const responseData = await createAndUploadFile(workbook, request); - logger.info('File updated successfully:' + JSON.stringify(responseData)); - if (responseData?.[0]?.fileStoreId) { - request.body.ResourceDetails.processedFileStoreId = responseData?.[0]?.fileStoreId; +function adjustRef(worksheet: any, lastColumn: any) { + const range = getSheetDataFromWorksheet(worksheet).filter( + (row: any) => row + ).length; // Get the number of used rows + worksheet.views = [ + { state: "frozen", ySplit: 1, topLeftCell: "A2", activeCell: "A2" }, + ]; + worksheet.autoFilter = { + from: { + row: 1, + column: 1, + }, + to: { + row: range, + column: worksheet.getColumn(lastColumn).number, + }, + }; +} + +function processErrorData( + request: any, + createAndSearchConfig: any, + workbook: any, + sheetName: any, + localizationMap?: { [key: string]: string } +) { + const worksheet = workbook.getWorksheet(sheetName); + var errorData = request.body.sheetErrorDetails; + const userNameAndPassword = request.body.userNameAndPassword; + const columns: any = findColumns(worksheet); + const statusColumn = columns.statusColumn; + const errorDetailsColumn = columns.errorDetailsColumn; + const additionalDetailsErrors: any[] = []; + errorData = mergeErrors(errorData); + enrichErrors( + errorData, + worksheet, + statusColumn, + errorDetailsColumn, + additionalDetailsErrors, + createAndSearchConfig, + localizationMap + ); + enrichActiveAndUUidColumn(worksheet, createAndSearchConfig, request); + + request.body.additionalDetailsErrors = request?.body?.additionalDetailsErrors + ? request?.body?.additionalDetailsErrors.concat(additionalDetailsErrors) + : additionalDetailsErrors; + + // Determine the last column to set the worksheet ref + const lastColumn = deterMineLastColumnAndEnrichUserDetails( + worksheet, + errorDetailsColumn, + userNameAndPassword, + request, + createAndSearchConfig + ); + + // Adjust the worksheet ref to include the last column + adjustRef(worksheet, lastColumn); + updateFontNameToRoboto(worksheet); + + workbook.xlsx.writeBuffer(); +} + +function mergeErrors(errorData: any) { + const errorMap: any = {}; + + errorData.forEach((item: any) => { + const { rowNumber, sheetName, status, errorDetails, ...rest } = item; + + // If the rowNumber already exists, merge the errorDetails + if (errorMap[rowNumber]) { + errorMap[rowNumber].errorDetails += "; " + errorDetails; } else { - throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); - } + // If not, add a new entry + errorMap[rowNumber] = { + rowNumber, + sheetName, + status, + errorDetails, + ...rest, + }; + } + }); + + // Convert the errorMap back into an array + return Object.values(errorMap); +} + +function processErrorDataForEachSheets( + request: any, + createAndSearchConfig: any, + workbook: any, + sheetName: any +) { + const desiredSheet = workbook.getWorksheet(sheetName); + const columns: any = findColumns(desiredSheet); + const statusColumn = columns.statusColumn; + const errorDetailsColumn = columns.errorDetailsColumn; + const userNameAndPassword = request?.body?.userNameAndPassword; + + var errorData = request.body.sheetErrorDetails.filter( + (error: any) => error.sheetName === sheetName + ); + const additionalDetailsErrors: any = []; + errorData = mergeErrors(errorData); + if (errorData) { + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; + if (error.isUniqueIdentifier) { + const uniqueIdentifierCell = + createAndSearchConfig.uniqueIdentifierColumn + rowIndex; + desiredSheet.getCell(uniqueIdentifierCell).value = + error.uniqueIdentifier; + } + + const statusCell = statusColumn + rowIndex; + const errorDetailsCell = errorDetailsColumn + rowIndex; + desiredSheet.getCell(statusCell).value = error.status; + desiredSheet.getCell(errorDetailsCell).value = error.errorDetails; + + if (!(error.status === "CREATED" || error.status === "VALID")) { + additionalDetailsErrors.push(error); + } + }); + } + if (userNameAndPassword) { + var newUserNameAndPassword: any = []; + for (const data of userNameAndPassword) { + const rowArray = data.rowNumber; + for (let i = 0; i < rowArray.length; i++) { + if (rowArray[i].sheetName == sheetName) { + newUserNameAndPassword.push({ ...data, rowNumber: rowArray[i].row }); + } + } + } + } + deterMineLastColumnAndEnrichUserDetails( + desiredSheet, + errorDetailsColumn, + newUserNameAndPassword, + request, + createAndSearchConfig + ); + request.body.additionalDetailsErrors = request?.body?.additionalDetailsErrors + ? request?.body?.additionalDetailsErrors.concat(additionalDetailsErrors) + : additionalDetailsErrors; + updateFontNameToRoboto(desiredSheet); + workbook.worksheets[sheetName] = desiredSheet; +} + +async function updateStatusFile( + request: any, + localizationMap?: { [key: string]: string } +) { + const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; + const tenantId = request?.body?.ResourceDetails?.tenantId; + const createAndSearchConfig = + createAndSearch[request?.body?.ResourceDetails?.type]; + const fileResponse = await httpRequest( + config.host.filestore + config.paths.filestore + "/url", + {}, + { tenantId: tenantId, fileStoreIds: fileStoreId }, + "get" + ); + const isLockSheetNeeded = + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ? true + : false; + + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "INVALID_FILE"); + } + const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; + const sheetName = createAndSearchConfig?.parseArrayConfig?.sheetName; + const localizedSheetName = getLocalizedName(sheetName, localizationMap); + const workbook: any = await getExcelWorkbookFromFileURL( + fileUrl, + localizedSheetName + ); + const worksheet: any = workbook.getWorksheet(localizedSheetName); + if (request?.body?.ResourceDetails?.type == "user") { + const columnsToUnhide = ["G", "H", "J", "K"]; + unhideColumnsOfProcessedFile(worksheet, columnsToUnhide); + } + processErrorData( + request, + createAndSearchConfig, + workbook, + localizedSheetName, + localizationMap + ); + + // Set column widths + const columnWidths = Array(12).fill({ width: 30 }); + columnWidths.forEach((colWidth, index) => { + if (worksheet.getColumn(index + 1)) { + worksheet.getColumn(index + 1).width = colWidth.width; + } + }); + if (isLockSheetNeeded) lockSheet(request, workbook); + const responseData = await createAndUploadFile(workbook, request); + + logger.info("File updated successfully:" + JSON.stringify(responseData)); + if (responseData?.[0]?.fileStoreId) { + request.body.ResourceDetails.processedFileStoreId = + responseData?.[0]?.fileStoreId; + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } +} +async function updateStatusFileForEachSheets( + request: any, + localizationMap?: { [key: string]: string } +) { + const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; + const tenantId = request?.body?.ResourceDetails?.tenantId; + const createAndSearchConfig = + createAndSearch[request?.body?.ResourceDetails?.type]; + const fileResponse = await httpRequest( + config.host.filestore + config.paths.filestore + "/url", + {}, + { tenantId: tenantId, fileStoreIds: fileStoreId }, + "get" + ); + const isLockSheetNeeded = + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ? true + : false; + + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "INVALID_FILE"); + } + + const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; + + const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, ""); + + const sheetNames = workbook.worksheets.map( + (worksheet: any) => worksheet.name + ); + const localizedSheetNames = getLocalizedHeaders(sheetNames, localizationMap); + + const sheetErrorDetails = request?.body?.sheetErrorDetails; + if (sheetErrorDetails && sheetErrorDetails?.length > 0) { + const firstError = sheetErrorDetails[0]; + if (Array.isArray(firstError?.rowNumber)) { + var newSheetErrorDetails: any = []; + for (const error of sheetErrorDetails) { + for (let i = 0; i < error.rowNumber.length; i++) { + newSheetErrorDetails.push({ + ...error, + rowNumber: error.rowNumber[i]?.row, + sheetName: error.rowNumber[i]?.sheetName, + }); + } + } + request.body.sheetErrorDetails = newSheetErrorDetails; + } + } + + localizedSheetNames.forEach((sheetName: any) => { + if ( + sheetName !== + getLocalizedName(config?.boundary?.boundaryTab, localizationMap) && + sheetName !== + getLocalizedName(config.values.readMeTab, localizationMap) && + sheetName !== + getLocalizedName("USER_MICROPLAN_SHEET_ROLES", localizationMap) + ) { + processErrorDataForEachSheets( + request, + createAndSearchConfig, + workbook, + sheetName + ); + } + }); + if (isLockSheetNeeded) lockSheet(request, workbook); + const responseData = await createAndUploadFile(workbook, request); + logger.info("File updated successfully:" + JSON.stringify(responseData)); + if (responseData?.[0]?.fileStoreId) { + request.body.ResourceDetails.processedFileStoreId = + responseData?.[0]?.fileStoreId; + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } } - function convertToType(dataToSet: any, type: any) { - switch (type) { - case "string": - return String(dataToSet); - case "number": - return Number(dataToSet); - case "boolean": - // Convert to boolean assuming any truthy value should be true and falsy should be false - return Boolean(dataToSet); - // Add more cases if needed for other types - default: - // If type is not recognized, keep dataToSet as it is - return dataToSet; - } + switch (type) { + case "string": + return String(dataToSet); + case "number": + return Number(dataToSet); + case "boolean": + // Convert to boolean assuming any truthy value should be true and falsy should be false + return Boolean(dataToSet); + // Add more cases if needed for other types + default: + // If type is not recognized, keep dataToSet as it is + return dataToSet; + } } function setTenantId( - resultantElement: any, - requestBody: any, - createAndSearchConfig: any + resultantElement: any, + requestBody: any, + createAndSearchConfig: any ) { - if (createAndSearchConfig?.parseArrayConfig?.tenantId) { - const tenantId = _.get(requestBody, createAndSearchConfig?.parseArrayConfig?.tenantId?.getValueViaPath); - _.set(resultantElement, createAndSearchConfig?.parseArrayConfig?.tenantId?.resultantPath, tenantId); - } - -} - - -async function processData(request: any, dataFromSheet: any[], createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { - const parseLogic = createAndSearchConfig?.parseArrayConfig?.parseLogic; - const requiresToSearchFromSheet = createAndSearchConfig?.requiresToSearchFromSheet; - var createData = [], searchData = []; - for (const data of dataFromSheet) { - const resultantElement: any = {}; - for (const element of parseLogic) { - if (element?.resultantPath) { - const localizedSheetColumnName = getLocalizedName(element.sheetColumnName, localizationMap); - let dataToSet = _.get(data, localizedSheetColumnName); - if (element.conversionCondition) { - dataToSet = element.conversionCondition[dataToSet]; - } - if (element.type) { - dataToSet = convertToType(dataToSet, element.type); - } - _.set(resultantElement, element.resultantPath, dataToSet); - } + if (createAndSearchConfig?.parseArrayConfig?.tenantId) { + const tenantId = _.get( + requestBody, + createAndSearchConfig?.parseArrayConfig?.tenantId?.getValueViaPath + ); + _.set( + resultantElement, + createAndSearchConfig?.parseArrayConfig?.tenantId?.resultantPath, + tenantId + ); + } +} + +async function processData( + request: any, + dataFromSheet: any[], + createAndSearchConfig: any, + localizationMap?: { [key: string]: string } +) { + const parseLogic = createAndSearchConfig?.parseArrayConfig?.parseLogic; + const requiresToSearchFromSheet = + createAndSearchConfig?.requiresToSearchFromSheet; + const isSourceMicroplan = + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan"; + var createData = [], + searchData = []; + for (const data of dataFromSheet) { + const resultantElement: any = {}; + for (const element of parseLogic) { + if (element?.resultantPath) { + const localizedSheetColumnName = getLocalizedName( + element.sheetColumnName, + localizationMap + ); + let dataToSet = _.get(data, localizedSheetColumnName); + if (element.conversionCondition) { + dataToSet = element.conversionCondition[dataToSet]; } - resultantElement["!row#number!"] = data["!row#number!"]; - var addToCreate = true; - if (requiresToSearchFromSheet) { - for (const key of requiresToSearchFromSheet) { - const localizedSheetColumnName = getLocalizedName(key.sheetColumnName, localizationMap); - if (data[localizedSheetColumnName]) { - searchData.push(resultantElement) - addToCreate = false; - break; - } - } + if (element.type) { + dataToSet = convertToType(dataToSet, element.type); } - if (addToCreate) { - createData.push(resultantElement) + _.set(resultantElement, element.resultantPath, dataToSet); + } + } + resultantElement["!row#number!"] = data["!row#number!"]; + var addToCreate = true; + if (requiresToSearchFromSheet) { + for (const key of requiresToSearchFromSheet) { + const localizedSheetColumnName = getLocalizedName( + key.sheetColumnName, + localizationMap + ); + if (data[localizedSheetColumnName]) { + if (isSourceMicroplan) { + changeCreateDataForMicroplan( + request, + resultantElement, + data, + localizationMap + ); + } + searchData.push(resultantElement); + addToCreate = false; + break; } - } - return { searchData, createData }; -} - -function setTenantIdAndSegregate(processedData: any, createAndSearchConfig: any, requestBody: any) { - for (const resultantElement of processedData.createData) { - setTenantId(resultantElement, requestBody, createAndSearchConfig); - } - for (const resultantElement of processedData.searchData) { - setTenantId(resultantElement, requestBody, createAndSearchConfig); - } - return processedData; + } + } + if (addToCreate) { + if (isSourceMicroplan) { + changeCreateDataForMicroplan( + request, + resultantElement, + data, + localizationMap + ); + } + createData.push(resultantElement); + } + } + return { searchData, createData }; +} + +function setTenantIdAndSegregate( + processedData: any, + createAndSearchConfig: any, + requestBody: any +) { + for (const resultantElement of processedData.createData) { + setTenantId(resultantElement, requestBody, createAndSearchConfig); + } + for (const resultantElement of processedData.searchData) { + setTenantId(resultantElement, requestBody, createAndSearchConfig); + } + return processedData; } // Original function divided into two parts -async function convertToTypeData(request: any, dataFromSheet: any[], createAndSearchConfig: any, requestBody: any, localizationMap?: { [key: string]: string }) { - const processedData = await processData(request, dataFromSheet, createAndSearchConfig, localizationMap); - return setTenantIdAndSegregate(processedData, createAndSearchConfig, requestBody); +async function convertToTypeData( + request: any, + dataFromSheet: any[], + createAndSearchConfig: any, + requestBody: any, + localizationMap?: { [key: string]: string } +) { + const processedData = await processData( + request, + dataFromSheet, + createAndSearchConfig, + localizationMap + ); + return setTenantIdAndSegregate( + processedData, + createAndSearchConfig, + requestBody + ); } function updateActivityResourceId(request: any) { - if (request?.body?.Activities && Array.isArray(request?.body?.Activities)) { - for (const activity of request?.body?.Activities) { - activity.resourceDetailsId = request?.body?.ResourceDetails?.id - } + if (request?.body?.Activities && Array.isArray(request?.body?.Activities)) { + for (const activity of request?.body?.Activities) { + activity.resourceDetailsId = request?.body?.ResourceDetails?.id; } + } } -async function generateProcessedFileAndPersist(request: any, localizationMap?: { [key: string]: string }) { - if (request.body.ResourceDetails.type == 'boundaryWithTarget') { - await updateStatusFileForTargets(request, localizationMap); - } else { - if (request.body.ResourceDetails.type !== "boundary") { - await updateStatusFile(request, localizationMap); - } - } - updateActivityResourceId(request); - request.body.ResourceDetails = { - ...request?.body?.ResourceDetails, - status: request.body.ResourceDetails.status != resourceDataStatuses.invalid ? resourceDataStatuses.completed : resourceDataStatuses.invalid, - auditDetails: { - ...request?.body?.ResourceDetails?.auditDetails, - lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, - lastModifiedTime: Date.now() - }, - additionalDetails: { ...request?.body?.ResourceDetails?.additionalDetails, sheetErrors: request?.body?.additionalDetailsErrors } || {} +async function generateProcessedFileAndPersist( + request: any, + localizationMap?: { [key: string]: string } +) { + if ( + request.body.ResourceDetails.type == "boundaryWithTarget" || + (request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" && + request.body.ResourceDetails.type == "user") + ) { + await updateStatusFileForEachSheets(request, localizationMap); + } else { + if ( + request.body.ResourceDetails.type !== "boundary" && + request.body.ResourceDetails.type !== "boundaryManagement" + ) { + await updateStatusFile(request, localizationMap); + } + } + updateActivityResourceId(request); + request.body.ResourceDetails = { + ...request?.body?.ResourceDetails, + status: + request.body.ResourceDetails.status != resourceDataStatuses.invalid + ? resourceDataStatuses.completed + : resourceDataStatuses.invalid, + auditDetails: { + ...request?.body?.ResourceDetails?.auditDetails, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + }, + additionalDetails: { + ...request?.body?.ResourceDetails?.additionalDetails, + sheetErrors: request?.body?.additionalDetailsErrors, + source: + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ? "microplan" + : null, + }, + }; + if ( + request?.body?.ResourceDetails?.status === resourceDataStatuses.completed && + request?.body?.ResourceDetails?.type === "boundaryManagement" + ) { + // delete redis cache key with prefix boundaryRelatiionshipSearch + await deleteRedisCacheKeysWithPrefix("boundaryRelationShipSearch"); + + logger.info( + "calling generate after boundary data uploaded under type boundary management" + ); + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, }; - const persistMessage: any = { ResourceDetails: request.body.ResourceDetails } - if (request?.body?.ResourceDetails?.action == "create") { - persistMessage.ResourceDetails.additionalDetails = {} - } - await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); - logger.info(`ResourceDetails to persist : ${request.body.ResourceDetails.type}`); - if (request?.body?.Activities && Array.isArray(request?.body?.Activities) && request?.body?.Activities.length > 0) { - logger.info("Activities to persist : ") - logger.debug(getFormattedStringForDebug(request?.body?.Activities)); - logger.info(`Waiting for 2 seconds`); - await new Promise(resolve => setTimeout(resolve, 2000)); - const activityObject = request?.body?.Activities; - await produceModifiedMessages(activityObject, config.kafka.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); - } + const params = { + type: request?.body?.ResourceDetails?.type, + tenantId: request?.body?.ResourceDetails?.tenantId, + forceUpdate: "true", + hierarchyType: request?.body?.ResourceDetails?.hierarchyType, + campaignId: "default", + }; + const newRequestBoundary = replicateRequest( + request, + newRequestBody, + params + ); + setTimeout(async () => { + // Code to be executed after 10 seconds + logger.info("Timeout of 10 sec after boundary data creation"); + await callGenerate( + newRequestBoundary, + request?.body?.ResourceDetails?.type + ); + }, 10000); + } + const persistMessage: any = { ResourceDetails: request.body.ResourceDetails }; + if (request?.body?.ResourceDetails?.action == "create") { + persistMessage.ResourceDetails.additionalDetails = { + source: + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ? "microplan" + : null, + fileName: + request?.body?.ResourceDetails?.additionalDetails?.fileName || null, + }; + } + await produceModifiedMessages( + persistMessage, + config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC + ); + logger.info( + `ResourceDetails to persist : ${request.body.ResourceDetails.type}` + ); + if ( + request?.body?.Activities && + Array.isArray(request?.body?.Activities) && + request?.body?.Activities.length > 0 + ) { + logger.info("Activities to persist : "); + logger.debug(getFormattedStringForDebug(request?.body?.Activities)); + logger.info(`Waiting for 2 seconds`); + await new Promise((resolve) => setTimeout(resolve, 2000)); + const activities = request?.body?.Activities; + for (let i = 0; i < activities.length; i += 10) { + const chunk = activities.slice(i, Math.min(i + 10, activities.length)); + const activityObject: any = { Activities: chunk }; + await produceModifiedMessages( + activityObject, + config.kafka.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC + ); + } + } } function getRootBoundaryCode(boundaries: any[] = []) { - for (const boundary of boundaries) { - if (boundary.isRoot) { - return boundary.code; - } + for (const boundary of boundaries) { + if (boundary.isRoot) { + return boundary.code; } - return ""; + } + return ""; } function enrichRootProjectId(requestBody: any) { - var rootBoundary; - for (const boundary of requestBody?.CampaignDetails?.boundaries) { - if (boundary?.isRoot) { - rootBoundary = boundary?.code - break; - } - } - if (rootBoundary) { - requestBody.CampaignDetails.projectId = requestBody?.boundaryProjectMapping?.[rootBoundary]?.projectId || null + var rootBoundary; + for (const boundary of requestBody?.boundariesCombined) { + if (boundary?.isRoot) { + rootBoundary = boundary?.code; + break; } - requestBody.CampaignDetails.projectId = requestBody.CampaignDetails.projectId || null + } + if (rootBoundary) { + requestBody.CampaignDetails.projectId = + requestBody?.boundaryProjectMapping?.[rootBoundary]?.projectId || null; + } + requestBody.CampaignDetails.projectId = + requestBody.CampaignDetails.projectId || null; } async function enrichAndPersistCampaignWithError(requestBody: any, error: any) { - requestBody.CampaignDetails = requestBody?.CampaignDetails || {} - const action = requestBody?.CampaignDetails?.action; - requestBody.CampaignDetails.campaignNumber = requestBody?.CampaignDetails?.campaignNumber || null - requestBody.CampaignDetails.campaignDetails = requestBody?.CampaignDetails?.campaignDetails || { deliveryRules: requestBody?.CampaignDetails?.deliveryRules, resources: requestBody?.CampaignDetails?.resources || [], boundaries: requestBody?.CampaignDetails?.boundaries || [] }; - requestBody.CampaignDetails.status = campaignStatuses?.failed; - requestBody.CampaignDetails.boundaryCode = getRootBoundaryCode(requestBody?.CampaignDetails?.boundaries) || null - requestBody.CampaignDetails.projectType = requestBody?.CampaignDetails?.projectType || null; - requestBody.CampaignDetails.hierarchyType = requestBody?.CampaignDetails?.hierarchyType || null; - requestBody.CampaignDetails.additionalDetails = requestBody?.CampaignDetails?.additionalDetails || {}; - requestBody.CampaignDetails.startDate = requestBody?.CampaignDetails?.startDate || null - requestBody.CampaignDetails.endDate = requestBody?.CampaignDetails?.endDate || null - requestBody.CampaignDetails.auditDetails = { - createdBy: requestBody?.RequestInfo?.userInfo?.uuid, - createdTime: Date.now(), - lastModifiedBy: requestBody?.RequestInfo?.userInfo?.uuid, - lastModifiedTime: Date.now(), - } - if (action == "create" && !requestBody?.CampaignDetails?.projectId) { - enrichRootProjectId(requestBody); - } - else if (!requestBody?.CampaignDetails?.projectId) { - requestBody.CampaignDetails.projectId = null - } - requestBody.CampaignDetails.additionalDetails = { - ...requestBody?.CampaignDetails?.additionalDetails, - error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) - } - const topic = config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC - // wait for 2 seconds - logger.info(`Waiting for 2 seconds to persist errors`); - await new Promise(resolve => setTimeout(resolve, 2000)); - const produceMessage: any = { CampaignDetails: requestBody.CampaignDetails } - await produceModifiedMessages(produceMessage, topic); - await persistTrack(requestBody?.CampaignDetails?.id, processTrackTypes.error, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); - delete requestBody.CampaignDetails.campaignDetails -} - -async function enrichAndPersistCampaignForCreate(request: any, firstPersist: boolean = false) { - const action = request?.body?.CampaignDetails?.action; - if (firstPersist) { - request.body.CampaignDetails.campaignNumber = await getCampaignNumber(request.body, "CMP-[cy:yyyy-MM-dd]-[SEQ_EG_CMP_ID]", "campaign.number", request?.body?.CampaignDetails?.tenantId); - } - request.body.CampaignDetails.campaignDetails = { deliveryRules: request?.body?.CampaignDetails?.deliveryRules || [], resources: request?.body?.CampaignDetails?.resources || [], boundaries: request?.body?.CampaignDetails?.boundaries || [] }; - request.body.CampaignDetails.status = action == "create" ? campaignStatuses.started : campaignStatuses.drafted; - request.body.CampaignDetails.boundaryCode = getRootBoundaryCode(request.body.CampaignDetails.boundaries) - request.body.CampaignDetails.projectType = request?.body?.CampaignDetails?.projectType || null; - request.body.CampaignDetails.hierarchyType = request?.body?.CampaignDetails?.hierarchyType || null; - request.body.CampaignDetails.additionalDetails = request?.body?.CampaignDetails?.additionalDetails || {}; - request.body.CampaignDetails.startDate = request?.body?.CampaignDetails?.startDate || null - request.body.CampaignDetails.endDate = request?.body?.CampaignDetails?.endDate || null - request.body.CampaignDetails.auditDetails = { - createdBy: request?.body?.RequestInfo?.userInfo?.uuid, - createdTime: Date.now(), - lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, - lastModifiedTime: Date.now(), - } - if (action == "create" && !request?.body?.CampaignDetails?.projectId && !firstPersist) { - enrichRootProjectId(request.body); - } - else { - request.body.CampaignDetails.projectId = null - } - const topic = firstPersist ? config?.kafka?.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC : config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC - delete request.body.CampaignDetails.codesTargetMapping - const produceMessage: any = { - CampaignDetails: request?.body?.CampaignDetails - }; - await produceModifiedMessages(produceMessage, topic); - delete request.body.CampaignDetails.campaignDetails -} - -function enrichInnerCampaignDetails(request: any, updatedInnerCampaignDetails: any) { - updatedInnerCampaignDetails.resources = request?.body?.CampaignDetails?.resources || [] - updatedInnerCampaignDetails.deliveryRules = request?.body?.CampaignDetails?.deliveryRules || [] - updatedInnerCampaignDetails.boundaries = request?.body?.CampaignDetails?.boundaries || [] + if (requestBody?.parentCampaign) { + await makeParentInactiveOrActive(requestBody, true); + } + requestBody.CampaignDetails = requestBody?.CampaignDetails || {}; + const action = requestBody?.CampaignDetails?.action; + requestBody.CampaignDetails.campaignNumber = + requestBody?.CampaignDetails?.campaignNumber || null; + requestBody.CampaignDetails.campaignDetails = requestBody?.CampaignDetails + ?.campaignDetails || { + deliveryRules: requestBody?.CampaignDetails?.deliveryRules, + resources: requestBody?.CampaignDetails?.resources || [], + boundaries: requestBody?.CampaignDetails?.boundaries || [], + }; + requestBody.CampaignDetails.status = campaignStatuses?.failed; + // requestBody.CampaignDetails.isActive = false; + requestBody.CampaignDetails.boundaryCode = + getRootBoundaryCode(requestBody?.CampaignDetails?.boundaries) || null; + requestBody.CampaignDetails.projectType = + requestBody?.CampaignDetails?.projectType || null; + requestBody.CampaignDetails.hierarchyType = + requestBody?.CampaignDetails?.hierarchyType || null; + requestBody.CampaignDetails.additionalDetails = + requestBody?.CampaignDetails?.additionalDetails || {}; + requestBody.CampaignDetails.startDate = + requestBody?.CampaignDetails?.startDate || null; + requestBody.CampaignDetails.endDate = + requestBody?.CampaignDetails?.endDate || null; + requestBody.CampaignDetails.auditDetails = { + createdBy: requestBody?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedBy: requestBody?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + }; + if (action == "create" && !requestBody?.CampaignDetails?.projectId) { + enrichRootProjectId(requestBody); + } else if (!requestBody?.CampaignDetails?.projectId) { + requestBody.CampaignDetails.projectId = null; + } + requestBody.CampaignDetails.additionalDetails = { + ...requestBody?.CampaignDetails?.additionalDetails, + error: String( + error?.message + (error?.description ? ` : ${error?.description}` : "") || + error + ), + }; + const topic = config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC; + // wait for 2 seconds + logger.info(`Waiting for 2 seconds to persist errors`); + await new Promise((resolve) => setTimeout(resolve, 2000)); + const produceMessage: any = { CampaignDetails: requestBody.CampaignDetails }; + await produceModifiedMessages(produceMessage, topic); + await persistTrack( + requestBody?.CampaignDetails?.id, + processTrackTypes.error, + processTrackStatuses.failed, + { + error: String( + error?.message + + (error?.description ? ` : ${error?.description}` : "") || error + ), + } + ); + delete requestBody.CampaignDetails.campaignDetails; +} + +async function enrichAndPersistCampaignForCreate( + request: any, + firstPersist: boolean = false +) { + const action = request?.body?.CampaignDetails?.action; + if (firstPersist) { + if (!request?.body?.parentCampaign) { + request.body.CampaignDetails.campaignNumber = await getCampaignNumber( + request.body, + "CMP-[cy:yyyy-MM-dd]-[SEQ_EG_CMP_ID]", + "campaign.number", + request?.body?.CampaignDetails?.tenantId + ); + } else { + request.body.CampaignDetails.campaignNumber = + request.body.parentCampaign?.campaignNumber; + request.body.CampaignDetails.campaignName = + request.body.parentCampaign?.campaignName; + } + } + request.body.CampaignDetails.campaignDetails = { + deliveryRules: request?.body?.CampaignDetails?.deliveryRules || [], + resources: request?.body?.CampaignDetails?.resources || [], + boundaries: request?.body?.CampaignDetails?.boundaries || [], + }; + request.body.CampaignDetails.status = + action == "create" ? campaignStatuses.started : campaignStatuses.drafted; + request.body.CampaignDetails.boundaryCode = getRootBoundaryCode( + request.body.CampaignDetails.boundaries + ); + request.body.CampaignDetails.projectType = + request?.body?.CampaignDetails?.projectType || null; + request.body.CampaignDetails.hierarchyType = + request?.body?.CampaignDetails?.hierarchyType || null; + request.body.CampaignDetails.additionalDetails = + request?.body?.CampaignDetails?.additionalDetails || {}; + request.body.CampaignDetails.startDate = + request?.body?.CampaignDetails?.startDate || null; + request.body.CampaignDetails.endDate = + request?.body?.CampaignDetails?.endDate || null; + request.body.CampaignDetails.auditDetails = { + createdBy: request?.body?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + }; + if ( + action == "create" && + !request?.body?.CampaignDetails?.projectId && + !firstPersist + ) { + enrichRootProjectId(request.body); + } else { + request.body.CampaignDetails.projectId = null; + } + const topic = firstPersist + ? config?.kafka?.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC + : config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC; + delete request.body.CampaignDetails.codesTargetMapping; + const produceMessage: any = { + CampaignDetails: request?.body?.CampaignDetails, + }; + await produceModifiedMessages(produceMessage, topic); + delete request.body.CampaignDetails.campaignDetails; +} + +function enrichInnerCampaignDetails( + request: any, + updatedInnerCampaignDetails: any +) { + updatedInnerCampaignDetails.resources = + request?.body?.CampaignDetails?.resources || []; + updatedInnerCampaignDetails.deliveryRules = + request?.body?.CampaignDetails?.deliveryRules || []; + updatedInnerCampaignDetails.boundaries = + request?.body?.CampaignDetails?.boundaries || []; } - -async function enrichAndPersistCampaignForUpdate(request: any, firstPersist: boolean = false) { - const action = request?.body?.CampaignDetails?.action; - const existingCampaignDetails = request?.body?.ExistingCampaignDetails; - callGenerateIfBoundariesDiffer(request); - if (existingCampaignDetails) { - if (areBoundariesSame(existingCampaignDetails?.boundaries, request?.body?.CampaignDetails?.boundaries)) { - updateTargetColumnsIfDeliveryConditionsDifferForSMC(request); - } - } - const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; - var updatedInnerCampaignDetails = {} - enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) - request.body.CampaignDetails.campaignNumber = ExistingCampaignDetails?.campaignNumber - request.body.CampaignDetails.campaignDetails = updatedInnerCampaignDetails - request.body.CampaignDetails.status = action == "changeDates" ? request.body.CampaignDetails.status : (action == "create" ? campaignStatuses.started : campaignStatuses.drafted); - const boundaryCode = !(request?.body?.CampaignDetails?.projectId) ? getRootBoundaryCode(request.body.CampaignDetails.boundaries) : (request?.body?.CampaignDetails?.boundaryCode || ExistingCampaignDetails?.boundaryCode) - request.body.CampaignDetails.boundaryCode = boundaryCode - request.body.CampaignDetails.startDate = request?.body?.CampaignDetails?.startDate || ExistingCampaignDetails?.startDate || null - request.body.CampaignDetails.endDate = request?.body?.CampaignDetails?.endDate || ExistingCampaignDetails?.endDate || null - request.body.CampaignDetails.projectType = request?.body?.CampaignDetails?.projectType ? request?.body?.CampaignDetails?.projectType : ExistingCampaignDetails?.projectType - request.body.CampaignDetails.hierarchyType = request?.body?.CampaignDetails?.hierarchyType ? request?.body?.CampaignDetails?.hierarchyType : ExistingCampaignDetails?.hierarchyType - request.body.CampaignDetails.additionalDetails = request?.body?.CampaignDetails?.additionalDetails ? request?.body?.CampaignDetails?.additionalDetails : ExistingCampaignDetails?.additionalDetails - request.body.CampaignDetails.auditDetails = { - createdBy: ExistingCampaignDetails?.createdBy, - createdTime: ExistingCampaignDetails?.createdTime, - lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, - lastModifiedTime: Date.now(), - } - if (action == "create" && !request?.body?.CampaignDetails?.projectId) { - enrichRootProjectId(request.body); - } - else { - request.body.CampaignDetails.projectId = request?.body?.CampaignDetails?.projectId || ExistingCampaignDetails?.projectId || null - } - delete request.body.CampaignDetails.codesTargetMapping - const producerMessage: any = { - CampaignDetails: request?.body?.CampaignDetails - } - await produceModifiedMessages(producerMessage, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC); - delete request.body.ExistingCampaignDetails - delete request.body.CampaignDetails.campaignDetails +async function enrichAndPersistCampaignForUpdate( + request: any, + firstPersist: boolean = false +) { + const action = request?.body?.CampaignDetails?.action; + const boundaries = request?.body?.boundariesCombined; + const existingCampaignDetails = request?.body?.ExistingCampaignDetails; + callGenerateIfBoundariesOrCampaignTypeDiffer(request); + if (existingCampaignDetails) { + if (areBoundariesSame(existingCampaignDetails?.boundaries, boundaries)) { + updateTargetColumnsIfDeliveryConditionsDifferForSMC(request); + } + } + const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + var updatedInnerCampaignDetails = {}; + enrichInnerCampaignDetails(request, updatedInnerCampaignDetails); + request.body.CampaignDetails.campaignNumber = + ExistingCampaignDetails?.campaignNumber; + request.body.CampaignDetails.campaignDetails = updatedInnerCampaignDetails; + request.body.CampaignDetails.status = + action == "changeDates" + ? request.body.CampaignDetails.status + : action == "create" + ? campaignStatuses.started + : campaignStatuses.drafted; + const boundaryCode = !request?.body?.CampaignDetails?.projectId + ? getRootBoundaryCode(request.body.CampaignDetails.boundaries) + : request?.body?.CampaignDetails?.boundaryCode || + ExistingCampaignDetails?.boundaryCode; + request.body.CampaignDetails.boundaryCode = boundaryCode; + request.body.CampaignDetails.startDate = + request?.body?.CampaignDetails?.startDate || + ExistingCampaignDetails?.startDate || + null; + request.body.CampaignDetails.endDate = + request?.body?.CampaignDetails?.endDate || + ExistingCampaignDetails?.endDate || + null; + request.body.CampaignDetails.projectType = request?.body?.CampaignDetails + ?.projectType + ? request?.body?.CampaignDetails?.projectType + : ExistingCampaignDetails?.projectType; + request.body.CampaignDetails.hierarchyType = request?.body?.CampaignDetails + ?.hierarchyType + ? request?.body?.CampaignDetails?.hierarchyType + : ExistingCampaignDetails?.hierarchyType; + request.body.CampaignDetails.additionalDetails = request?.body + ?.CampaignDetails?.additionalDetails + ? request?.body?.CampaignDetails?.additionalDetails + : ExistingCampaignDetails?.additionalDetails; + request.body.CampaignDetails.auditDetails = { + createdBy: ExistingCampaignDetails?.createdBy, + createdTime: ExistingCampaignDetails?.createdTime, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + }; + if (action == "create" && !request?.body?.CampaignDetails?.projectId) { + enrichRootProjectId(request.body); + } else { + request.body.CampaignDetails.projectId = + request?.body?.CampaignDetails?.projectId || + ExistingCampaignDetails?.projectId || + null; + } + delete request.body.CampaignDetails.codesTargetMapping; + const producerMessage: any = { + CampaignDetails: request?.body?.CampaignDetails, + }; + await produceModifiedMessages( + producerMessage, + config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC + ); + // delete request.body.ExistingCampaignDetails; + delete request.body.CampaignDetails.campaignDetails; +} + +async function makeParentInactiveOrActive(requestBody: any, active: boolean) { + let parentCampaign = requestBody?.parentCampaign; + parentCampaign.isActive = active; + parentCampaign.campaignDetails = { + deliveryRules: parentCampaign?.deliveryRules || [], + resources: parentCampaign?.resources || [], + boundaries: parentCampaign?.boundaries || [], + }; + parentCampaign.auditDetails.lastModifiedTime = Date.now(); + parentCampaign.auditDetails.lastModifiedBy = + requestBody?.RequestInfo?.userInfo?.uuid; + const produceMessage: any = { + CampaignDetails: parentCampaign, + }; + await produceModifiedMessages( + produceMessage, + config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC + ); } function getCreateResourceIds(resources: any[]) { - return resources - .filter((resource: any) => typeof resource.createResourceId === 'string' && resource.createResourceId.trim() !== '') - .map((resource: any) => { - const resourceId = resource.createResourceId; - return resourceId; - }); -} - -async function persistForCampaignProjectMapping(request: any, createResourceDetailsIds: any, localizationMap?: any) { - if (createResourceDetailsIds && request?.body?.CampaignDetails?.projectId) { - var requestBody: any = { - RequestInfo: request?.body?.RequestInfo, - Campaign: {} - } - requestBody.Campaign.id = request?.body?.CampaignDetails?.id - requestBody.Campaign.hierarchyType = request?.body?.CampaignDetails?.hierarchyType - requestBody.Campaign.tenantId = request?.body?.CampaignDetails?.tenantId - requestBody.Campaign.campaignName = request?.body?.CampaignDetails?.campaignName - requestBody.Campaign.boundaryCode = request?.body?.CampaignDetails?.boundaryCode - requestBody.Campaign.startDate = request?.body?.CampaignDetails?.startDate - requestBody.Campaign.endDate = request?.body?.CampaignDetails?.endDate - requestBody.Campaign.projectType = request?.body?.CampaignDetails?.projectType - requestBody.Campaign.additionalDetails = request?.body?.CampaignDetails?.additionalDetails - requestBody.Campaign.deliveryRules = request?.body?.CampaignDetails?.deliveryRules - requestBody.Campaign.rootProjectId = request?.body?.CampaignDetails?.projectId - requestBody.Campaign.resourceDetailsIds = createResourceDetailsIds - requestBody.CampaignDetails = request?.body?.CampaignDetails - var updatedInnerCampaignDetails = {} - enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) - requestBody.CampaignDetails = request?.body?.CampaignDetails - requestBody.CampaignDetails.campaignDetails = updatedInnerCampaignDetails - // requestBody.localizationMap = localizationMap - logger.info("Persisting CampaignProjectMapping..."); - logger.debug(`CampaignProjectMapping: ${getFormattedStringForDebug(requestBody)}`); - await produceModifiedMessages(requestBody, config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC); - } + return resources + .filter( + (resource: any) => + typeof resource.createResourceId === "string" && + resource.createResourceId.trim() !== "" + ) + .map((resource: any) => { + const resourceId = resource.createResourceId; + return resourceId; + }); } -function removeBoundariesFromRequest(request: any) { - if (request?.body?.CampaignDetails?.boundaries && Array.isArray(request?.body?.CampaignDetails?.boundaries) && request?.body?.CampaignDetails?.boundaries?.length > 0) { - request.body.CampaignDetails.boundaries = request?.body?.CampaignDetails?.boundaries?.filter((boundary: any) => !boundary?.insertedAfter) - } +async function persistForCampaignProjectMapping( + request: any, + createResourceDetailsIds: any, + localizationMap?: any +) { + if (createResourceDetailsIds && request?.body?.CampaignDetails?.projectId) { + var requestBody: any = { + RequestInfo: request?.body?.RequestInfo, + Campaign: {}, + }; + if (request?.body?.ExistingCampaignDetails) { + delete request.body.ExistingCampaignDetails; + } + requestBody.Campaign.id = request?.body?.CampaignDetails?.id; + // requestBody.Campaign.newlyCreatedBoundaryProjectMap = + // request?.body?.newlyCreatedBoundaryProjectMap; + requestBody.Campaign.hierarchyType = + request?.body?.CampaignDetails?.hierarchyType; + requestBody.Campaign.tenantId = request?.body?.CampaignDetails?.tenantId; + requestBody.Campaign.campaignName = + request?.body?.CampaignDetails?.campaignName; + requestBody.Campaign.boundaryCode = + request?.body?.CampaignDetails?.boundaryCode; + requestBody.Campaign.startDate = request?.body?.CampaignDetails?.startDate; + requestBody.Campaign.endDate = request?.body?.CampaignDetails?.endDate; + requestBody.Campaign.projectType = + request?.body?.CampaignDetails?.projectType; + requestBody.Campaign.additionalDetails = + request?.body?.CampaignDetails?.additionalDetails; + requestBody.Campaign.deliveryRules = + request?.body?.CampaignDetails?.deliveryRules; + requestBody.Campaign.rootProjectId = + request?.body?.CampaignDetails?.projectId; + requestBody.Campaign.resourceDetailsIds = createResourceDetailsIds; + requestBody.CampaignDetails = request?.body?.CampaignDetails; + requestBody.parentCampaign = request?.body?.parentCampaign; + var updatedInnerCampaignDetails = {}; + enrichInnerCampaignDetails(request, updatedInnerCampaignDetails); + requestBody.CampaignDetails = request?.body?.CampaignDetails; + requestBody.CampaignDetails.campaignDetails = updatedInnerCampaignDetails; + // requestBody.localizationMap = localizationMap + logger.info("Persisting CampaignProjectMapping..."); + logger.debug( + `CampaignProjectMapping: ${getFormattedStringForDebug(requestBody)}` + ); + await produceModifiedMessages( + requestBody, + config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC + ); + } } -async function enrichAndPersistProjectCampaignForFirst(request: any, actionInUrl: any, firstPersist: boolean = false, localizationMap?: any) { - removeBoundariesFromRequest(request); - if (actionInUrl == "create") { - await enrichAndPersistCampaignForCreate(request, firstPersist) - } - else if (actionInUrl == "update") { - await enrichAndPersistCampaignForUpdate(request, firstPersist) - } - if (request?.body?.CampaignDetails?.action == "create") { - await createProcessTracks(request.body.CampaignDetails.id) - } +function removeBoundariesFromRequest(request: any) { + const boundaries = request?.body?.CampaignDetails?.boundaries; + if (boundaries && Array.isArray(boundaries) && boundaries?.length > 0) { + request.body.CampaignDetails.boundaries = boundaries?.filter( + (boundary: any) => !boundary?.insertedAfter + ); + } } - -async function enrichAndPersistProjectCampaignRequest(request: any, actionInUrl: any, firstPersist: boolean = false, localizationMap?: any) { - var createResourceDetailsIds: any[] = [] - if (request?.body?.CampaignDetails?.resources && Array.isArray(request?.body?.CampaignDetails?.resources) && request?.body?.CampaignDetails?.resources?.length > 0 && request?.body?.CampaignDetails?.action == "create") { - createResourceDetailsIds = getCreateResourceIds(request?.body?.CampaignDetails?.resources); - } - removeBoundariesFromRequest(request); - if (actionInUrl == "create") { - await enrichAndPersistCampaignForCreate(request, firstPersist) - } - else if (actionInUrl == "update") { - await enrichAndPersistCampaignForUpdate(request, firstPersist) - } - if (request?.body?.CampaignDetails?.action == "create") { - await persistForCampaignProjectMapping(request, createResourceDetailsIds, localizationMap); - } +async function enrichAndPersistProjectCampaignForFirst( + request: any, + actionInUrl: any, + firstPersist: boolean = false, + localizationMap?: any +) { + removeBoundariesFromRequest(request); + if (actionInUrl == "create") { + await enrichAndPersistCampaignForCreate(request, firstPersist); + } else if (actionInUrl == "update") { + await enrichAndPersistCampaignForUpdate(request, firstPersist); + } + if (request?.body?.parentCampaign?.isActive) { + await makeParentInactiveOrActive(request?.body, false); + } + if (request?.body?.CampaignDetails?.action == "create") { + await createProcessTracks(request.body.CampaignDetails.id); + } +} + +async function enrichAndPersistProjectCampaignRequest( + request: any, + actionInUrl: any, + firstPersist: boolean = false, + localizationMap?: any +) { + var createResourceDetailsIds: any[] = []; + if ( + request?.body?.CampaignDetails?.resources && + Array.isArray(request?.body?.CampaignDetails?.resources) && + request?.body?.CampaignDetails?.resources?.length > 0 && + request?.body?.CampaignDetails?.action == "create" + ) { + createResourceDetailsIds = getCreateResourceIds( + request?.body?.CampaignDetails?.resources + ); + } + // removeBoundariesFromRequest(request); + if (actionInUrl == "create") { + await enrichAndPersistCampaignForCreate(request, firstPersist); + } else if (actionInUrl == "update") { + await enrichAndPersistCampaignForUpdate(request, firstPersist); + } + if (request?.body?.CampaignDetails?.action == "create") { + await persistForCampaignProjectMapping( + request, + createResourceDetailsIds, + localizationMap + ); + } } function getChildParentMap(modifiedBoundaryData: any) { - const childParentMap: Map<{ key: string, value: string }, { key: string, value: string } | null> = new Map(); - - modifiedBoundaryData.forEach((row: any) => { - for (let j = row.length - 1; j >= 0; j--) { - const child = row[j]; - const parent = j - 1 >= 0 ? row[j - 1] : null; - const childIdentifier = { key: child.key, value: child.value }; // Unique identifier for the child - const parentIdentifier = parent ? { key: parent.key, value: parent.value } : null; // Unique identifier for the parent, set to null if parent doesn't exist - - - // Check if the mapping already exists in the childParentMap - const existingMapping = Array.from(childParentMap.entries()).find(([existingChild, existingParent]) => - _.isEqual(existingChild, childIdentifier) && _.isEqual(existingParent, parentIdentifier) - ); - - // If the mapping doesn't exist, add it to the childParentMap - if (!existingMapping) { - childParentMap.set(childIdentifier, parentIdentifier); - } - } - }); - return childParentMap; + const childParentMap: Map< + { key: string; value: string }, + { key: string; value: string } | null + > = new Map(); + + modifiedBoundaryData.forEach((row: any) => { + for (let j = row.length - 1; j >= 0; j--) { + const child = row[j]; + const parent = j - 1 >= 0 ? row[j - 1] : null; + const childIdentifier = { key: child.key, value: child.value }; // Unique identifier for the child + const parentIdentifier = parent + ? { key: parent.key, value: parent.value } + : null; // Unique identifier for the parent, set to null if parent doesn't exist + + // Check if the mapping already exists in the childParentMap + const existingMapping = Array.from(childParentMap.entries()).find( + ([existingChild, existingParent]) => + _.isEqual(existingChild, childIdentifier) && + _.isEqual(existingParent, parentIdentifier) + ); + + // If the mapping doesn't exist, add it to the childParentMap + if (!existingMapping) { + childParentMap.set(childIdentifier, parentIdentifier); + } + } + }); + return childParentMap; } - - - - - function getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode: any[]) { - const countMap = new Map<{ key: string, value: string }, number>(); - const mappingMap = new Map<{ key: string, value: string }, string>(); - - withBoundaryCode.forEach((row: any[]) => { - const len = row.length; - if (len >= 3) { - let grandParentFound = false; - const grandParent = row[len - 3]; - if (findMapValue(mappingMap, grandParent)) { - const countMapArray = Array.from(countMap.entries()); - for (const [key, value] of countMapArray) { - if (_.isEqual(key, grandParent)) { - countMap.set(key, value + 1); - grandParentFound = true; - break; - } - } - if (grandParentFound == false) { - countMap.set(grandParent, 1); - } - } + const countMap = new Map<{ key: string; value: string }, number>(); + const mappingMap = new Map<{ key: string; value: string }, string>(); + + withBoundaryCode.forEach((row: any[]) => { + const len = row.length; + if (len >= 3) { + let grandParentFound = false; + const grandParent = row[len - 3]; + if (findMapValue(mappingMap, grandParent)) { + const countMapArray = Array.from(countMap.entries()); + for (const [key, value] of countMapArray) { + if (_.isEqual(key, grandParent)) { + countMap.set(key, value + 1); + grandParentFound = true; + break; + } } - mappingMap.set(row[len - 2], row[len - 1].value); - }); - return { mappingMap, countMap }; + if (grandParentFound == false) { + countMap.set(grandParent, 1); + } + } + } + mappingMap.set(row[len - 2], row[len - 1].value); + }); + return { mappingMap, countMap }; } - -function addBoundaryCodeToData(withBoundaryCode: any[], withoutBoundaryCode: any[], boundaryMap: Map) { - const boundaryDataWithBoundaryCode = withBoundaryCode; - const modifiedBoundaryDataWithBoundaryCode = boundaryDataWithBoundaryCode.map((array) => { - return array.map((obj: any) => { - if (obj.key === 'Boundary Code') { - return obj.value; - } else { - return obj; - } - }); - }); - - const boundaryDataForWithoutBoundaryCode = withoutBoundaryCode.map((row: any[]) => { - const boundaryName = row[row.length - 1]; // Get the last element of the row - const boundaryCode = findMapValue(boundaryMap, boundaryName); // Fetch corresponding boundary code from map - return [...row, boundaryCode]; // Append boundary code to the row and return updated row - }); - const boundaryDataForSheet = [...modifiedBoundaryDataWithBoundaryCode, ...boundaryDataForWithoutBoundaryCode]; - return boundaryDataForSheet; -} - -function prepareDataForExcel(boundaryDataForSheet: any, hierarchy: any[], boundaryMap: any) { - const data = boundaryDataForSheet.map((boundary: any[]) => { - const boundaryCode = boundary.pop(); - const boundaryValues = boundary.map(obj => obj.value); - const rowData = boundaryValues.concat(Array(Math.max(0, hierarchy.length - boundary.length)).fill('')); - const boundaryCodeIndex = hierarchy.length; - rowData[boundaryCodeIndex] = boundaryCode; - return rowData; - }); - return data; -} -function extractCodesFromBoundaryRelationshipResponse(boundaries: any[]): any { - const codes = new Set(); - for (const boundary of boundaries) { - codes.add(boundary.code); // Add code to the Set - if (boundary.children && boundary.children.length > 0) { - const childCodes = extractCodesFromBoundaryRelationshipResponse(boundary.children); // Recursively get child codes - childCodes.forEach((code: any) => codes.add(code)); // Add child codes to the Set +function addBoundaryCodeToData( + withBoundaryCode: any[], + withoutBoundaryCode: any[], + boundaryMap: Map +) { + const boundaryDataWithBoundaryCode = withBoundaryCode; + const modifiedBoundaryDataWithBoundaryCode = boundaryDataWithBoundaryCode.map( + (array) => { + return array.map((obj: any) => { + if (obj.key === "Boundary Code") { + return obj.value; + } else { + return obj; } + }); } - return codes; -} - - -async function getTotalCount(request: any) { - const CampaignDetails = request.body.CampaignDetails; - const { tenantId, pagination, ids, ...searchFields } = CampaignDetails; - let conditions = []; - let values = [tenantId]; - let index = 2; - const campaignsIncludeDates = searchFields?.campaignsIncludeDates - - for (const field in searchFields) { - if (searchFields[field] !== undefined && field != 'campaignsIncludeDates') { - if (field === 'startDate') { - const startDateSign = campaignsIncludeDates ? '<=' : '>='; - conditions.push(`startDate ${startDateSign} $${index}`); - values.push(searchFields[field]); - index++; - } else if (field === 'endDate') { - const endDateSign = campaignsIncludeDates ? '>=' : '<='; - conditions.push(`endDate ${endDateSign} $${index}`); - values.push(searchFields[field]); - index++; - } else if (field === 'campaignName') { - conditions.push(`${field} ILIKE '%' || $${index} || '%'`); - values.push(searchFields[field]); - index++; - } else if (field != 'status') { - conditions.push(`${field} = $${index}`); - values.push(searchFields[field]); - index++; - } - } + ); + + const boundaryDataForWithoutBoundaryCode = withoutBoundaryCode.map( + (row: any[]) => { + const boundaryName = row[row.length - 1]; // Get the last element of the row + const boundaryCode = findMapValue(boundaryMap, boundaryName); // Fetch corresponding boundary code from map + return [...row, boundaryCode]; // Append boundary code to the row and return updated row } + ); + const boundaryDataForSheet = [ + ...modifiedBoundaryDataWithBoundaryCode, + ...boundaryDataForWithoutBoundaryCode, + ]; + return boundaryDataForSheet; +} - let query = ` +function prepareDataForExcel( + boundaryDataForSheet: any, + hierarchy: any[], + boundaryMap: any +) { + const data = boundaryDataForSheet.map((boundary: any[]) => { + const boundaryCode = boundary.pop(); + const boundaryValues = boundary.map((obj) => obj.value); + const rowData = boundaryValues.concat( + Array(Math.max(0, hierarchy.length - boundary.length)).fill("") + ); + const boundaryCodeIndex = hierarchy.length; + rowData[boundaryCodeIndex] = boundaryCode; + return rowData; + }); + return data; +} +function extractCodesFromBoundaryRelationshipResponse(boundaries: any[]): any { + const codes = new Set(); + for (const boundary of boundaries) { + codes.add(boundary.code); // Add code to the Set + if (boundary.children && boundary.children.length > 0) { + const childCodes = extractCodesFromBoundaryRelationshipResponse( + boundary.children + ); // Recursively get child codes + childCodes.forEach((code: any) => codes.add(code)); // Add child codes to the Set + } + } + return codes; +} + +async function getTotalCount(campaignDetails: any) { + const { tenantId, pagination, ids, ...searchFields } = campaignDetails; + let conditions = []; + let values = [tenantId]; + let index = 2; + const campaignsIncludeDates = searchFields?.campaignsIncludeDates; + + for (const field in searchFields) { + if (searchFields[field] !== undefined && field != "campaignsIncludeDates") { + if (field === "startDate") { + const startDateSign = campaignsIncludeDates ? "<=" : ">="; + conditions.push(`startDate ${startDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === "endDate") { + const endDateSign = campaignsIncludeDates ? ">=" : "<="; + conditions.push(`endDate ${endDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === "campaignName") { + conditions.push(`${field} ILIKE '%' || $${index} || '%'`); + values.push(searchFields[field]); + index++; + } else if (field != "status") { + conditions.push(`${field} = $${index}`); + values.push(searchFields[field]); + index++; + } + } + } + + let query = ` SELECT count(*) FROM ${config?.DB_CONFIG.DB_CAMPAIGN_DETAILS_TABLE_NAME} WHERE tenantId = $1 `; - if (ids && ids.length > 0) { - const idParams = ids.map((id: any, i: any) => `$${index + i}`); - query += ` AND id IN (${idParams.join(', ')})`; - values.push(...ids); - index = index + ids.length; - } - var status = searchFields?.status; - if (status) { - if (typeof status === 'string') { - status = [status]; // Convert string to array - } - const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter - query += ` AND status IN (${statusParams.join(', ')})`; - values.push(...status); - } - - if (conditions.length > 0) { - query += ` AND ${conditions.join(' AND ')}`; - } - const queryResult = await executeQuery(query, values); - const totalCount = parseInt(queryResult.rows[0].count, 10); - request.body.totalCount = totalCount; -} - - - - -async function searchProjectCampaignResourcData(request: any) { - const CampaignDetails = request.body.CampaignDetails; - const { tenantId, pagination, ids, ...searchFields } = CampaignDetails; - const queryData = buildSearchQuery(tenantId, pagination, ids, searchFields); - await getTotalCount(request) - const responseData: any[] = await executeSearchQuery(queryData.query, queryData.values); - // TODO @ashish check the below code looks like duplicate - for (const data of responseData) { - data.resources = data?.campaignDetails?.resources - data.boundaries = data?.campaignDetails?.boundaries - data.deliveryRules = data?.campaignDetails?.deliveryRules; - delete data.campaignDetails; - data.auditDetails = { - createdBy: data?.createdBy, - lastModifiedBy: data?.lastModifiedBy, - createdTime: data?.createdTime, - lastModifiedTime: data?.lastModifiedTime - } - delete data.createdBy; - delete data.lastModifiedBy; - delete data.createdTime; - delete data.lastModifiedTime; - } - request.body.CampaignDetails = responseData; -} - -function buildSearchQuery(tenantId: string, pagination: any, ids: string[], searchFields: any): { query: string, values: any[] } { - let conditions = []; - let values = [tenantId]; - let index = 2; - const campaignsIncludeDates = searchFields?.campaignsIncludeDates - - for (const field in searchFields) { - if (searchFields[field] !== undefined && field != 'campaignsIncludeDates') { - if (field === 'startDate') { - const startDateSign = campaignsIncludeDates ? '<=' : '>='; - conditions.push(`startDate ${startDateSign} $${index}`); - values.push(searchFields[field]); - index++; - } else if (field === 'endDate') { - const endDateSign = campaignsIncludeDates ? '>=' : '<='; - conditions.push(`endDate ${endDateSign} $${index}`); - values.push(searchFields[field]); - index++; - } else if (field === 'campaignName') { - conditions.push(`${field} ILIKE '%' || $${index} || '%'`); - values.push(searchFields[field]); - index++; - } else if (field != 'status') { - conditions.push(`${field} = $${index}`); - values.push(searchFields[field]); - index++; - } - } - } - - let query = ` + if (ids && ids.length > 0) { + const idParams = ids.map((id: any, i: any) => `$${index + i}`); + query += ` AND id IN (${idParams.join(", ")})`; + values.push(...ids); + index = index + ids.length; + } else { + // If no IDs are provided, filter by isActive = true + query += ` AND isActive = true`; + } + var status = searchFields?.status; + if (status) { + if (typeof status === "string") { + status = [status]; // Convert string to array + } + const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter + query += ` AND status IN (${statusParams.join(", ")})`; + values.push(...status); + } + + if (conditions.length > 0) { + query += ` AND ${conditions.join(" AND ")}`; + } + const queryResult = await executeQuery(query, values); + const totalCount = parseInt(queryResult.rows[0].count, 10); + return totalCount; +} + +async function searchProjectCampaignResourcData(campaignDetails: any) { + // const CampaignDetails = request.body.CampaignDetails; + const { tenantId, pagination, ids, ...searchFields } = campaignDetails; + const queryData = buildSearchQuery(tenantId, pagination, ids, searchFields); + const totalCount = await getTotalCount(campaignDetails); + const responseData: any[] = await executeSearchQuery( + queryData.query, + queryData.values + ); + // TODO @ashish check the below code looks like duplicate + for (const data of responseData) { + data.resources = data?.campaignDetails?.resources; + data.boundaries = data?.campaignDetails?.boundaries; + data.deliveryRules = data?.campaignDetails?.deliveryRules; + delete data.campaignDetails; + data.auditDetails = { + createdBy: data?.createdBy, + lastModifiedBy: data?.lastModifiedBy, + createdTime: data?.createdTime, + lastModifiedTime: data?.lastModifiedTime, + }; + delete data.createdBy; + delete data.lastModifiedBy; + delete data.createdTime; + delete data.lastModifiedTime; + } + return { responseData, totalCount }; +} + +function buildSearchQuery( + tenantId: string, + pagination: any, + ids: string[], + searchFields: any +): { query: string; values: any[] } { + let conditions = []; + let values = [tenantId]; + let index = 2; + const campaignsIncludeDates = searchFields?.campaignsIncludeDates; + + for (const field in searchFields) { + if (searchFields[field] !== undefined && field != "campaignsIncludeDates") { + if (field === "startDate") { + const startDateSign = campaignsIncludeDates ? "<=" : ">="; + conditions.push(`startDate ${startDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === "endDate") { + const endDateSign = campaignsIncludeDates ? ">=" : "<="; + conditions.push(`endDate ${endDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === "campaignName") { + conditions.push(`${field} ILIKE '%' || $${index} || '%'`); + values.push(searchFields[field]); + index++; + } else if (field != "status") { + conditions.push(`${field} = $${index}`); + values.push(searchFields[field]); + index++; + } + } + } + + let query = ` SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_DETAILS_TABLE_NAME} WHERE tenantId = $1 `; - if (ids && ids.length > 0) { - const idParams = ids.map((id: any, i: any) => `$${index + i}`); - query += ` AND id IN (${idParams.join(', ')})`; - values.push(...ids); - index = index + ids.length; - } + if (ids && ids.length > 0) { + const idParams = ids.map((id: any, i: any) => `$${index + i}`); + query += ` AND id IN (${idParams.join(", ")})`; + values.push(...ids); + index = index + ids.length; + } else { + // If no IDs are provided, filter by isActive = true + query += ` AND isActive = true`; + } - var status = searchFields?.status; - if (status) { - if (typeof status === 'string') { - status = [status]; // Convert string to array - } - const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter - query += ` AND status IN (${statusParams.join(', ')})`; - values.push(...status); + var status = searchFields?.status; + if (status) { + if (typeof status === "string") { + status = [status]; // Convert string to array } + const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter + query += ` AND status IN (${statusParams.join(", ")})`; + values.push(...status); + } - if (conditions.length > 0) { - query += ` AND ${conditions.join(' AND ')}`; - } + if (conditions.length > 0) { + query += ` AND ${conditions.join(" AND ")}`; + } - if (pagination) { - query += '\n'; + if (pagination) { + query += "\n"; - if (pagination.sortBy) { - query += `ORDER BY ${pagination.sortBy}`; - if (pagination.sortOrder) { - query += ` ${pagination.sortOrder.toUpperCase()}`; - } - query += '\n'; - } + if (pagination.sortBy) { + query += `ORDER BY ${pagination.sortBy}`; + if (pagination.sortOrder) { + query += ` ${pagination.sortOrder.toUpperCase()}`; + } + query += "\n"; + } - if (pagination.limit !== undefined) { - query += `LIMIT ${pagination.limit}`; - if (pagination.offset !== undefined) { - query += ` OFFSET ${pagination.offset}`; - } - query += '\n'; - } + if (pagination.limit !== undefined) { + query += `LIMIT ${pagination.limit}`; + if (pagination.offset !== undefined) { + query += ` OFFSET ${pagination.offset}`; + } + query += "\n"; } + } - return { query, values }; + return { query, values }; } - - async function executeSearchQuery(query: string, values: any[]) { - const queryResult = await executeQuery(query, values); - return campaignDetailsTransformer(queryResult?.rows); + const queryResult = await executeQuery(query, values); + return campaignDetailsTransformer(queryResult?.rows); } async function processDataSearchRequest(request: any) { - const { SearchCriteria } = request.body; - const query = buildWhereClauseForDataSearch(SearchCriteria); - const queryResult = await executeQuery(query.query, query.values); - request.body.ResourceDetails = genericResourceTransformer(queryResult?.rows);; -} - -function buildWhereClauseForDataSearch(SearchCriteria: any): { query: string; values: any[] } { - const { id, tenantId, type, status } = SearchCriteria; - let conditions = []; - let values = []; - - if (id && id.length > 0) { - conditions.push(`id = ANY($${values.length + 1})`); - values.push(id); - } - - if (tenantId) { - conditions.push(`tenantId = $${values.length + 1}`); - values.push(tenantId); - } - - if (type) { - conditions.push(`type = $${values.length + 1}`); - values.push(type); - } - - if (status) { - conditions.push(`status = $${values.length + 1}`); - values.push(status); - } - - const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''; - - return { - query: ` - SELECT * - FROM ${config?.DB_CONFIG.DB_RESOURCE_DETAILS_TABLE_NAME} - ${whereClause};`, values - }; + const { SearchCriteria } = request.body; + const query = buildWhereClauseForDataSearch(SearchCriteria); + const queryResult = await executeQuery(query.query, query.values); + request.body.ResourceDetails = genericResourceTransformer(queryResult?.rows); +} + +function buildWhereClauseForDataSearch(SearchCriteria: any): { + query: string; + values: any[]; +} { + const { id, tenantId, type, status, hierarchyType } = SearchCriteria; + let conditions = []; + let values = []; + + // Check for id + if (id && id.length > 0) { + conditions.push(`id = ANY($${values.length + 1})`); + values.push(id); + } + + // Check for tenantId + if (tenantId) { + conditions.push(`tenantId = $${values.length + 1}`); + values.push(tenantId); + } + + // Check for type + if (type) { + conditions.push(`type = $${values.length + 1}`); + values.push(type); + } + + // Check for status + if (status) { + conditions.push(`status = $${values.length + 1}`); + values.push(status); + } + + // Check for hierarchyType + if (hierarchyType) { + conditions.push(`hierarchyType = $${values.length + 1}`); + values.push(hierarchyType); + } + + // Build the WHERE clause + const whereClause = + conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : ""; + + // Return the query and values array + return { + query: ` + SELECT * + FROM ${config?.DB_CONFIG.DB_RESOURCE_DETAILS_TABLE_NAME} + ${whereClause};`, + values, + }; } function mapBoundariesParent(boundaryResponse: any, request: any, parent: any) { - if (!boundaryResponse) return; - request.body.boundaryProjectMapping[boundaryResponse.code] = { - parent: parent || null, - projectId: null - } - if (boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { - for (const child of boundaryResponse.children) { - mapBoundariesParent(child, request, boundaryResponse.code); - } - } -} - -function mapTargets(boundaryResponses: any, codesTargetMapping: any) { - if (!boundaryResponses || !codesTargetMapping) return; - - for (const boundaryResponse of boundaryResponses) { - const mapBoundary = (boundary: any) => { - if (!boundary.children || boundary.children.length === 0) { - const targetValue = codesTargetMapping[boundary.code]; - return targetValue ? targetValue : 0; - } + if (!boundaryResponse) return; - let totalTargetValue = 0; - for (const child of boundary.children) { - const childTargetValue = mapBoundary(child); - totalTargetValue += childTargetValue; - } - codesTargetMapping[boundary.code] = totalTargetValue; - return totalTargetValue; - }; - mapBoundary(boundaryResponse); + request.body.boundaryProjectMapping[boundaryResponse.code] = { + parent: parent || null, + projectId: null, + }; + if ( + boundaryResponse?.children && + Array.isArray(boundaryResponse?.children) && + boundaryResponse?.children?.length > 0 + ) { + for (const child of boundaryResponse.children) { + mapBoundariesParent(child, request, boundaryResponse.code); } + } } - -async function processBoundary(boundaryResponse: any, boundaries: any, includeAllChildren: any, boundaryCodes: any, boundaryChildren: any) { - if (!boundaryResponse) return; - if (!boundaryCodes.has(boundaryResponse.code)) { - boundaries.push({ code: boundaryResponse?.code, type: boundaryResponse?.boundaryType, insertedAfter: true }); - boundaryCodes.add(boundaryResponse?.code); - } - if (includeAllChildren && boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { - for (const child of boundaryResponse.children) { - processBoundary(child, boundaries, true, boundaryCodes, boundaryChildren); - } - } - else if (boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { - for (const child of boundaryResponse.children) { - if (boundaryCodes.has(child.code) && boundaryChildren[child.code]) { - processBoundary(child, boundaries, true, boundaryCodes, boundaryChildren); - } - else if (boundaryCodes.has(child.code)) { - processBoundary(child, boundaries, false, boundaryCodes, boundaryChildren); - } - } - } +function mapTargets(boundaryResponses: any, codesTargetMapping: any) { + if (!boundaryResponses || !codesTargetMapping) return; + + for (const boundaryResponse of boundaryResponses) { + const mapBoundary = (boundary: any) => { + if (!boundary.children || boundary.children.length === 0) { + const targetValue = codesTargetMapping[boundary.code]; + return targetValue ? targetValue : 0; + } + + let totalTargetValue = 0; + for (const child of boundary.children) { + const childTargetValue = mapBoundary(child); + totalTargetValue += childTargetValue; + } + codesTargetMapping[boundary.code] = totalTargetValue; + return totalTargetValue; + }; + mapBoundary(boundaryResponse); + } } -async function addBoundaries(request: any, boundaryResponse: any, boundaryChildren: any) { - var { boundaries } = request?.body?.CampaignDetails; - var boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code)); - await processBoundary(boundaryResponse, boundaries, boundaryChildren[boundaryResponse?.code], boundaryCodes, boundaryChildren); - request.body.CampaignDetails.boundaries = boundaries +async function processBoundary( + boundaryResponse: any, + boundaries: any, + includeAllChildren: any, + boundaryCodes: any, + boundaryChildren: any +) { + if (!boundaryResponse) return; + if (!boundaryCodes.has(boundaryResponse.code)) { + boundaries.push({ + code: boundaryResponse?.code, + type: boundaryResponse?.boundaryType, + insertedAfter: true, + }); + boundaryCodes.add(boundaryResponse?.code); + } + if ( + includeAllChildren && + boundaryResponse?.children && + Array.isArray(boundaryResponse?.children) && + boundaryResponse?.children?.length > 0 + ) { + for (const child of boundaryResponse.children) { + processBoundary(child, boundaries, true, boundaryCodes, boundaryChildren); + } + } else if ( + boundaryResponse?.children && + Array.isArray(boundaryResponse?.children) && + boundaryResponse?.children?.length > 0 + ) { + for (const child of boundaryResponse.children) { + if (boundaryCodes.has(child.code) && boundaryChildren[child.code]) { + processBoundary( + child, + boundaries, + true, + boundaryCodes, + boundaryChildren + ); + } else if (boundaryCodes.has(child.code)) { + processBoundary( + child, + boundaries, + false, + boundaryCodes, + boundaryChildren + ); + } + } + } +} + +async function addBoundaries( + request: any, + boundaryResponse: any, + boundaryChildren: any +) { + var boundaries = request?.body?.boundariesCombined; + var boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code)); + await processBoundary( + boundaryResponse, + boundaries, + boundaryChildren[boundaryResponse?.code], + boundaryCodes, + boundaryChildren + ); + request.body.boundariesCombined = boundaries; } async function addBoundariesForData(request: any, CampaignDetails: any) { - var { boundaries } = CampaignDetails; - const rootBoundary = getRootBoundaryCode(boundaries) - if (rootBoundary) { - const params = { - tenantId: request?.body?.ResourceDetails?.tenantId, - codes: rootBoundary, - hierarchyType: request?.body?.ResourceDetails?.hierarchyType, - includeChildren: true - } - const header = { - ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, - } - const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, params, undefined, undefined, header); - if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { - var boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { - acc[boundary.code] = boundary?.includeAllChildren; - return acc; - }, {}); - var boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code)); - await processBoundary(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], boundaries, boundaryChildren[boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]?.code], boundaryCodes, boundaryChildren); - CampaignDetails.boundaries = boundaries - } - else { - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Some internal server error occured during boundary validation."); - } - } - else { - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "There is no root boundary for this campaign."); - } + // var { boundaries } = CampaignDetails; + var boundaries = await getBoundariesFromCampaignSearchResponse( + request, + CampaignDetails + ); + const rootBoundary = getRootBoundaryCode(boundaries); + if (rootBoundary) { + const params = { + tenantId: request?.body?.ResourceDetails?.tenantId, + codes: rootBoundary, + hierarchyType: request?.body?.ResourceDetails?.hierarchyType, + includeChildren: true, + }; + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId + }${params.codes || ""}${params?.includeChildren || ""}`, + }; + const boundaryResponse = await httpRequest( + config.host.boundaryHost + config.paths.boundaryRelationship, + request.body, + params, + undefined, + undefined, + header + ); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + var boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { + acc[boundary.code] = boundary?.includeAllChildren; + return acc; + }, {}); + var boundaryCodes = new Set( + boundaries.map((boundary: any) => boundary.code) + ); + await processBoundary( + boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], + boundaries, + boundaryChildren[ + boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]?.code + ], + boundaryCodes, + boundaryChildren + ); + CampaignDetails.boundaries = boundaries; + } else { + throwError( + "COMMON", + 500, + "INTERNAL_SERVER_ERROR", + "Some internal server error occured during boundary validation." + ); + } + } else { + throwError( + "COMMON", + 500, + "INTERNAL_SERVER_ERROR", + "There is no root boundary for this campaign." + ); + } } -function reorderBoundariesWithParentFirst(reorderedBoundaries: any[], boundaryProjectMapping: any) { - // Function to get the index of a boundary in the original boundaries array - function getIndex(code: any, boundaries: any[]) { - return reorderedBoundaries.findIndex((boundary: any) => boundary.code === code); - } - // Reorder boundaries so that parents come first - for (let i = 0; i < 2 * (reorderedBoundaries?.length); i++) { - for (const boundary of reorderedBoundaries) { - const parentCode = boundaryProjectMapping[boundary.code]?.parent; - if (parentCode) { - const parentIndex = getIndex(parentCode, reorderedBoundaries); - const boundaryIndex = getIndex(boundary.code, reorderedBoundaries); +function reorderBoundariesWithParentFirst( + boundaries: any[], + boundaryProjectMapping: any +) { + const startTime = Date.now(); + + const boundaryGraph = new Map(); + const inDegree = new Map(); + + logger.info(`Started processing ${boundaries.length} boundaries...`); + + // Step 1: Build the graph and calculate in-degrees + boundaries.forEach((boundary) => { + const code = boundary.code; + boundaryGraph.set(code, []); + inDegree.set(code, 0); // Initialize in-degree for each boundary + }); + + boundaries.forEach((boundary) => { + const code = boundary.code; + const parentCode = boundaryProjectMapping[code]?.parent; + + if (parentCode) { + boundaryGraph.get(parentCode).push(code); // Parent points to child + inDegree.set(code, inDegree.get(code) + 1); // Increment in-degree of child + } + }); + + const graphConstructionTime = Date.now(); + logger.info( + `Graph construction completed. Time taken: ${( + (graphConstructionTime - startTime) / 1000 + ).toFixed(2)} seconds.` + ); + + // Step 2: Perform topological sort using Kahn's Algorithm + const queue: any = []; + const sortedBoundaries = []; + + // Enqueue nodes with 0 in-degree + boundaries.forEach((boundary) => { + if (inDegree.get(boundary.code) === 0) { + queue.push(boundary); + } + }); + + let nodesProcessed = 0; + while (queue.length > 0) { + const currentBoundary = queue.shift(); + sortedBoundaries.push(currentBoundary); + nodesProcessed++; + + // Log progress periodically + if (nodesProcessed % 500 === 0) { + const elapsed = (Date.now() - startTime) / 1000; + const avgTimePerBoundary = elapsed / nodesProcessed; + const estimatedRemaining = avgTimePerBoundary * (boundaries.length - nodesProcessed); + logger.info( + `Processed ${nodesProcessed} boundaries. Elapsed: ${elapsed.toFixed( + 2 + )} seconds. Estimated time remaining: ${estimatedRemaining.toFixed(2)} seconds.` + ); + } + + const children = boundaryGraph.get(currentBoundary.code) || []; + children.forEach((childCode: any) => { + inDegree.set(childCode, inDegree.get(childCode) - 1); + if (inDegree.get(childCode) === 0) { + queue.push( + boundaries.find((boundary) => boundary.code === childCode) + ); + } + }); + } - if (parentIndex !== -1 && boundaryIndex !== -1 && parentIndex > boundaryIndex) { - reorderedBoundaries.splice(parentIndex + 1, 0, reorderedBoundaries.splice(boundaryIndex, 1)[0]); - break; - } - } - } - } + // Check for cycles (remaining nodes with non-zero in-degree) + if (sortedBoundaries.length !== boundaries.length) { + throw new Error( + "Cycle detected in the boundary-parent relationships. Reordering failed." + ); + } + + const endTime = Date.now(); + logger.info( + `Reordering completed. Processed ${boundaries.length} boundaries in ${( + (endTime - startTime) / 1000 + ).toFixed(2)} seconds.` + ); + + return sortedBoundaries; } -async function reorderBoundariesOfDataAndValidate(request: any, localizationMap?: any) { - if (request?.body?.ResourceDetails?.campaignId) { - const searchBody = { - RequestInfo: request?.body?.RequestInfo, - CampaignDetails: { - ids: [request?.body?.ResourceDetails?.campaignId], - tenantId: request?.body?.ResourceDetails?.tenantId - } - } - const req: any = replicateRequest(request, searchBody) - const response = await searchProjectTypeCampaignService(req) - if (response?.CampaignDetails?.[0]) { - const CampaignDetails = response?.CampaignDetails?.[0] - await addBoundariesForData(request, CampaignDetails) - logger.debug("Boundaries after addition " + getFormattedStringForDebug(CampaignDetails?.boundaries)); - await validateBoundaryOfResouces(CampaignDetails, request, localizationMap) - } - else { - throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while Validating sheet boundaries"); - } +async function reorderBoundariesOfDataAndValidate( + request: any, + localizationMap?: any +) { + if (request?.body?.ResourceDetails?.campaignId) { + // const searchBody = { + // RequestInfo: request?.body?.RequestInfo, + const CampaignDetails = { + ids: [request?.body?.ResourceDetails?.campaignId], + tenantId: request?.body?.ResourceDetails?.tenantId, + } + // }; + // const req: any = replicateRequest(request, searchBody); + const response = await searchProjectTypeCampaignService(CampaignDetails); + if (response?.CampaignDetails?.[0]) { + const CampaignDetails = response?.CampaignDetails?.[0]; + await addBoundariesForData(request, CampaignDetails); + logger.debug( + "Boundaries after addition " + + getFormattedStringForDebug(CampaignDetails?.boundaries) + ); + await validateBoundaryOfResouces( + CampaignDetails, + request, + localizationMap + ); + } else { + throwError( + "CAMPAIGN", + 400, + "CAMPAIGN_NOT_FOUND", + "Campaign not found while Validating sheet boundaries" + ); } + } } async function reorderBoundaries(request: any, localizationMap?: any) { - var { boundaries } = request?.body?.CampaignDetails; - const rootBoundary = getRootBoundaryCode(boundaries) - request.body.boundaryProjectMapping = {} - if (rootBoundary) { - const params = { - tenantId: request?.body?.CampaignDetails?.tenantId, - codes: rootBoundary, - hierarchyType: request?.body?.CampaignDetails?.hierarchyType, - includeChildren: true - } - const header = { - ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, - } - const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, params, undefined, undefined, header); - if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { - const codesTargetMapping = await getCodesTarget(request, localizationMap) - mapTargets(boundaryResponse?.TenantBoundary?.[0]?.boundary, codesTargetMapping) - request.body.CampaignDetails.codesTargetMapping = codesTargetMapping - logger.debug("codesTargetMapping mapping :: " + getFormattedStringForDebug(codesTargetMapping)); - mapBoundariesParent(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], request, null) - var boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { - acc[boundary.code] = boundary?.includeAllChildren; - return acc; - }, {}); - await addBoundaries(request, boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], boundaryChildren) - } - else { - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Some internal server error occured during boundary validation."); - } - } - else { - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "There is no root boundary for this campaign."); - } - logger.info("Boundaries for campaign creation in received") - logger.debug("Boundaries after addition " + getFormattedStringForDebug(request?.body?.CampaignDetails?.boundaries)); - reorderBoundariesWithParentFirst(request?.body?.CampaignDetails?.boundaries, request?.body?.boundaryProjectMapping) - logger.info("Reordered the Boundaries for mapping"); - logger.debug("Reordered Boundaries " + getFormattedStringForDebug(request?.body?.CampaignDetails?.boundaries)); + // var { boundaries } = request?.body?.CampaignDetails; + var boundaries = request?.body?.boundariesCombined; + const rootBoundary = getRootBoundaryCode(boundaries); + request.body.boundaryProjectMapping = {}; + if (rootBoundary) { + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + codes: rootBoundary, + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + includeChildren: true, + }; + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId + }${params.codes || ""}${params?.includeChildren || ""}`, + }; + const boundaryResponse = await httpRequest( + config.host.boundaryHost + config.paths.boundaryRelationship, + request.body, + params, + undefined, + undefined, + header + ); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + const codesTargetMapping = await getCodesTarget(request, localizationMap); + if (codesTargetMapping) { + mapTargets( + boundaryResponse?.TenantBoundary?.[0]?.boundary, + codesTargetMapping + ); + request.body.CampaignDetails.codesTargetMapping = codesTargetMapping; + logger.debug( + "codesTargetMapping mapping :: " + + getFormattedStringForDebug(codesTargetMapping) + ); + } + mapBoundariesParent( + boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], + request, + null + ); + var boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { + acc[boundary.code] = boundary?.includeAllChildren; + return acc; + }, {}); + await addBoundaries( + request, + boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], + boundaryChildren + ); + } else { + throwError( + "COMMON", + 500, + "INTERNAL_SERVER_ERROR", + "Some internal server error occured during boundary validation." + ); + } + } else { + throwError( + "COMMON", + 500, + "INTERNAL_SERVER_ERROR", + "There is no root boundary for this campaign." + ); + } + logger.info("Boundaries for campaign creation in received"); + logger.debug( + "Boundaries after addition " + + getFormattedStringForDebug(request?.body?.boundariesCombined) + ); + const start = Date.now(); + const sortedBoundaries = reorderBoundariesWithParentFirst( + request?.body?.boundariesCombined, + request?.body?.boundaryProjectMapping + ); + request.body.boundariesCombined = sortedBoundaries; + const end = Date.now(); + logger.info(`Execution time: ${(end - start) / 1000} seconds`); + logger.info("Reordered the Boundaries for mapping"); + logger.debug( + "Reordered Boundaries " + + getFormattedStringForDebug(request?.body?.boundariesCombined) + ); + return request.body.boundariesCombined; } function convertToProjectsArray(Projects: any, currentArray: any = []) { - for (const project of Projects) { - const descendants = project?.descendants - delete project?.descendants - currentArray.push(project); - if (descendants && Array.isArray(descendants) && descendants?.length > 0) { - convertToProjectsArray(descendants, currentArray) - } + for (const project of Projects) { + const descendants = project?.descendants; + delete project?.descendants; + currentArray.push(project); + if (descendants && Array.isArray(descendants) && descendants?.length > 0) { + convertToProjectsArray(descendants, currentArray); } - return currentArray; + } + return currentArray; } async function getRelatedProjects(request: any) { - const { projectId, tenantId } = request?.body?.CampaignDetails; - const projectSearchBody = { - RequestInfo: request?.body?.RequestInfo, - Projects: [ - { - id: projectId, - tenantId: tenantId - } - ] - } - const projectSearchParams = { + const { projectId, tenantId } = request?.body?.CampaignDetails; + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo, + Projects: [ + { + id: projectId, tenantId: tenantId, - offset: 0, - limit: 1, - includeDescendants: true - } - logger.info("Project search params " + JSON.stringify(projectSearchParams)) - const projectSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectSearch, projectSearchBody, projectSearchParams); - if (projectSearchResponse?.Project && Array.isArray(projectSearchResponse?.Project) && projectSearchResponse?.Project?.length > 0) { - return convertToProjectsArray(projectSearchResponse?.Project) - } - else { - throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR") - return [] - } + }, + ], + }; + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1, + includeDescendants: true, + }; + logger.info("Project search params " + JSON.stringify(projectSearchParams)); + const projectSearchResponse = await httpRequest( + config?.host?.projectHost + config?.paths?.projectSearch, + projectSearchBody, + projectSearchParams + ); + if ( + projectSearchResponse?.Project && + Array.isArray(projectSearchResponse?.Project) && + projectSearchResponse?.Project?.length > 0 + ) { + return convertToProjectsArray(projectSearchResponse?.Project); + } else { + throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR"); + return []; + } } async function updateProjectDates(request: any, actionInUrl: any) { - const { startDate, endDate, projectId } = request?.body?.CampaignDetails - if ((startDate || endDate) && projectId && actionInUrl == "update") { - const projects = await getRelatedProjects(request); - for (const project of projects) { - project.startDate = startDate || project.startDate; - project.endDate = endDate || project.endDate; - delete project?.address; - } - logger.info("Projects related to current Campaign : " + JSON.stringify(projects)); - const projectUpdateBody = { - RequestInfo: request?.body?.RequestInfo, - Projects: projects - } - const projectUpdateResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectUpdate, projectUpdateBody); - if (projectUpdateResponse?.Project && Array.isArray(projectUpdateResponse?.Project) && projectUpdateResponse?.Project?.length == projects?.length) { - logger.info("Project dates updated successfully") - } - else { - throwError("PROJECT", 500, "PROJECT_UPDATE_ERROR") - } + const { startDate, endDate, projectId } = request?.body?.CampaignDetails; + if ((startDate || endDate) && projectId && actionInUrl == "update") { + const projects = await getRelatedProjects(request); + for (const project of projects) { + project.startDate = startDate || project.startDate; + project.endDate = endDate || project.endDate; + delete project?.address; + } + logger.info( + "Projects related to current Campaign : " + JSON.stringify(projects) + ); + const projectUpdateBody = { + RequestInfo: request?.body?.RequestInfo, + Projects: projects, + }; + const projectUpdateResponse = await httpRequest( + config?.host?.projectHost + config?.paths?.projectUpdate, + projectUpdateBody + ); + if ( + projectUpdateResponse?.Project && + Array.isArray(projectUpdateResponse?.Project) && + projectUpdateResponse?.Project?.length == projects?.length + ) { + logger.info("Project dates updated successfully"); + } else { + throwError("PROJECT", 500, "PROJECT_UPDATE_ERROR"); } + } } async function getCodesTarget(request: any, localizationMap?: any) { - const { tenantId, resources } = request?.body?.CampaignDetails; - const boundaryWithTargetResource = resources?.filter((resource: any) => resource?.type == "boundaryWithTarget"); - const fileId = boundaryWithTargetResource[0]?.filestoreId - const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileId }, "get"); + let boundaryCodesWhoseTargetsHasToBeUpdated: any = []; + const { tenantId, resources } = request?.body?.CampaignDetails; + const boundaryWithTargetResource = resources?.filter( + (resource: any) => resource?.type == "boundaryWithTarget" + ); + if (boundaryWithTargetResource && boundaryWithTargetResource.length > 0) { + const fileId = boundaryWithTargetResource[0]?.filestoreId; + const fileResponse = await httpRequest( + config.host.filestore + config.paths.filestore + "/url", + {}, + { tenantId: tenantId, fileStoreIds: fileId }, + "get" + ); if (!fileResponse?.fileStoreIds?.[0]?.url) { - throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); + throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); } - const codeColumnName = getLocalizedName(createAndSearch?.boundaryWithTarget?.boundaryValidation?.column, localizationMap) - const targetData = await getTargetSheetDataAfterCode(fileResponse?.fileStoreIds?.[0]?.url, true, true, codeColumnName); + const codeColumnName = getLocalizedName( + createAndSearch?.boundaryWithTarget?.boundaryValidation?.column, + localizationMap + ); + const targetData = await getTargetSheetDataAfterCode( + request, + fileResponse?.fileStoreIds?.[0]?.url, + true, + true, + codeColumnName + ); const boundaryTargetMapping: any = {}; // Iterate through each key in targetData for (const key in targetData) { - // Iterate through each entry in the array under the current key - targetData[key].forEach(entry => { - // Check if the entry has both "Boundary Code" and "Target at the Selected Boundary level" - if (entry[codeColumnName] !== undefined && entry['Target at the Selected Boundary level'] !== undefined) { - // Add the mapping to the boundaryTargetMapping object - boundaryTargetMapping[entry[codeColumnName]] = entry['Target at the Selected Boundary level']; - } - }); + // Iterate through each entry in the array under the current key + targetData[key].forEach((entry) => { + // Check if the entry has both "Boundary Code" and "Target at the Selected Boundary level" + if ( + entry[codeColumnName] !== undefined && + entry["Target at the Selected Boundary level"] !== undefined + ) { + // Add the mapping to the boundaryTargetMapping object + boundaryTargetMapping[entry[codeColumnName]] = + entry["Target at the Selected Boundary level"]; + if ( + entry["Parent Target at the Selected Boundary level"] !== 0 && + entry["Parent Target at the Selected Boundary level"] !== + entry["Target at the Selected Boundary level"] + ) { + boundaryCodesWhoseTargetsHasToBeUpdated.push(entry[codeColumnName]); + } + } + }); } - logger.info("Boundary target mapping count" + Object.keys(boundaryTargetMapping)?.length); + logger.info( + "Boundary target mapping count" + + Object.keys(boundaryTargetMapping)?.length + ); + request.body.boundaryCodesWhoseTargetsHasToBeUpdated = + boundaryCodesWhoseTargetsHasToBeUpdated; return boundaryTargetMapping; + } else return null; } -async function createProject(request: any, actionUrl: any, localizationMap?: any) { - await persistTrack(request.body.CampaignDetails.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.inprogress); - try { - logger.info("Create Projects started for the given Campaign") - var { tenantId, boundaries, projectType, projectId } = request?.body?.CampaignDetails; - if (boundaries && projectType && !projectId) { - const projectTypeResponse = await getMDMSV1Data({}, 'HCM-PROJECT-TYPES', "projectTypes", tenantId); - var Projects: any = enrichProjectDetailsFromCampaignDetails(request?.body?.CampaignDetails, projectTypeResponse?.filter((types: any) => types?.code == projectType)?.[0]); - const projectCreateBody = { +async function createProject( + request: any, + actionUrl: any, + localizationMap?: any +) { + await persistTrack( + request.body.CampaignDetails.id, + processTrackTypes.targetAndDeliveryRulesCreation, + processTrackStatuses.inprogress + ); + try { + logger.info("Create Projects started for the given Campaign"); + var { tenantId, projectType, projectId } = request?.body?.CampaignDetails; + var boundaries = request?.body?.boundariesCombined; + if (boundaries && projectType && !projectId) { + const projectTypeResponse = await getMDMSV1Data( + {}, + "HCM-PROJECT-TYPES", + "projectTypes", + tenantId + ); + var Projects: any = enrichProjectDetailsFromCampaignDetails( + request?.body?.CampaignDetails, + projectTypeResponse?.filter( + (types: any) => types?.code == projectType + )?.[0] + ); + const projectCreateBody = { + RequestInfo: request?.body?.RequestInfo, + Projects, + }; + boundaries = await reorderBoundaries(request, localizationMap); + let boundariesAlreadyWithProjects: any; + if (request?.body?.parentCampaign) { + // make search to project with parent campaign root project id + const { projectId, tenantId } = request?.body?.parentCampaign; + const projectSearchResponse = + await fetchProjectsWithProjectId(request, projectId, tenantId); + boundariesAlreadyWithProjects = + getBoundaryProjectMappingFromParentCampaign( + request, + projectSearchResponse?.Project?.[0] + ); + } + + const boundaryCodesWhoseTargetsHasToBeUpdated = + request?.body?.boundaryCodesWhoseTargetsHasToBeUpdated; + if (boundaryCodesWhoseTargetsHasToBeUpdated) { + for (const boundary of boundaryCodesWhoseTargetsHasToBeUpdated) { + if ( + boundariesAlreadyWithProjects && + boundariesAlreadyWithProjects.size > 0 && + boundariesAlreadyWithProjects.has(boundary) + ) { + const projectSearchResponse = + await fetchProjectsWithBoundaryCodeAndReferenceId( + boundary, + tenantId, + request?.body?.CampaignDetails?.campaignNumber, + request?.body?.RequestInfo + ); + const projectToUpdate = projectSearchResponse?.Project?.[0]; + if (projectToUpdate) { + const filteredTargets = projectToUpdate.targets.filter( + (e: any) => + e.beneficiaryType == + request?.body?.CampaignDetails?.additionalDetails + ?.beneficiaryType + ); + if (filteredTargets.length == 0) { + projectToUpdate.targets = [ + { + beneficiaryType: + request?.body?.CampaignDetails?.additionalDetails + ?.beneficiaryType, + totalNo: + request?.body?.CampaignDetails?.codesTargetMapping[ + boundary + ], + targetNo: + request?.body?.CampaignDetails?.codesTargetMapping[ + boundary + ], + }, + ]; + } else { + const targetobj = filteredTargets[0]; + (targetobj.totalNo = + request?.body?.CampaignDetails?.codesTargetMapping[boundary]), + (targetobj.targetNo = + request?.body?.CampaignDetails?.codesTargetMapping[ + boundary + ]); + projectToUpdate.targets = [targetobj]; + } + const projectUpdateBody = { RequestInfo: request?.body?.RequestInfo, - Projects - } - await reorderBoundaries(request, localizationMap) - boundaries = request?.body?.CampaignDetails?.boundaries; - for (const boundary of boundaries) { - Projects[0].address = { tenantId: tenantId, boundary: boundary?.code, boundaryType: boundary?.type } - if (request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent) { - const parent = request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent - await confirmProjectParentCreation(request, request?.body?.boundaryProjectMapping?.[parent]?.projectId) - Projects[0].parent = request?.body?.boundaryProjectMapping?.[parent]?.projectId - } - else { - Projects[0].parent = null - } - Projects[0].referenceID = request?.body?.CampaignDetails?.id - Projects[0].targets = [ - { - beneficiaryType: request?.body?.CampaignDetails?.additionalDetails?.beneficiaryType, - totalNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code], - targetNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code] - } - ] - await projectCreate(projectCreateBody, request) + Projects: [projectToUpdate], + }; + + await projectUpdateForTargets( + projectUpdateBody, + request, + boundary + ); } + } } - } catch (error: any) { - console.log(error) - await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); - throw new Error(error) - } - await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.completed); + } + delete request.body.boundaryCodesWhoseTargetsHasToBeUpdated; + for (const boundary of boundaries) { + const boundaryCode = boundary?.code; + // Only proceed if the boundary code is not already mapped to an existing project + if ( + !boundariesAlreadyWithProjects || + (boundariesAlreadyWithProjects.size > 0 && + !boundariesAlreadyWithProjects.has(boundaryCode)) + ) { + // Set the address for the project + Projects[0].address = { + tenantId: tenantId, + boundary: boundaryCode, + boundaryType: boundary?.type, + }; + + // Handle parent project assignment if present in boundaryProjectMapping + const parent = + request?.body?.boundaryProjectMapping?.[boundaryCode]?.parent; + const parentProjectId = + request?.body?.boundaryProjectMapping?.[parent]?.projectId; + + if (parent && parentProjectId) { + await confirmProjectParentCreation(request, parentProjectId); + Projects[0].parent = parentProjectId; + } else { + Projects[0].parent = null; + } + + // Set the reference ID and project targets + Projects[0].referenceID = request?.body?.CampaignDetails?.campaignNumber; + (Projects[0].targets = [ + { + beneficiaryType: + request?.body?.CampaignDetails?.additionalDetails + ?.beneficiaryType, + totalNo: + request?.body?.CampaignDetails?.codesTargetMapping[ + boundaryCode + ], + targetNo: + request?.body?.CampaignDetails?.codesTargetMapping[ + boundaryCode + ], + }, + ]); + await projectCreate(projectCreateBody, request); + } + } + } + } catch (error: any) { + console.log(error); + await persistTrack( + request?.body?.CampaignDetails?.id, + processTrackTypes.targetAndDeliveryRulesCreation, + processTrackStatuses.failed, + { + error: String( + error?.message + + (error?.description ? ` : ${error?.description}` : "") || error + ), + } + ); + throw new Error(error); + } + await persistTrack( + request?.body?.CampaignDetails?.id, + processTrackTypes.targetAndDeliveryRulesCreation, + processTrackStatuses.completed + ); } - async function processAfterPersist(request: any, actionInUrl: any) { - try { - const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.CampaignDetails?.tenantId); - if (request?.body?.CampaignDetails?.action == "create") { - await persistTrack(request.body.CampaignDetails.id, processTrackTypes.validation, processTrackStatuses.completed); - await createProjectCampaignResourcData(request); - await createProject(request, actionInUrl, localizationMap) - await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) - } - else { - await updateProjectDates(request, actionInUrl); - await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) - } - } catch (error: any) { - console.log(error) - logger.error(error) - await enrichAndPersistCampaignWithError(request?.body, error) + try { + const localizationMap = await getLocalizedMessagesHandler( + request, + request?.body?.CampaignDetails?.tenantId + ); + if (request?.body?.CampaignDetails?.action == "create") { + await persistTrack( + request.body.CampaignDetails.id, + processTrackTypes.validation, + processTrackStatuses.completed + ); + await createProjectCampaignResourcData(request); + await createProject(request, actionInUrl, localizationMap); + await enrichAndPersistProjectCampaignRequest( + request, + actionInUrl, + false, + localizationMap + ); + } else { + await updateProjectDates(request, actionInUrl); + await enrichAndPersistProjectCampaignRequest( + request, + actionInUrl, + false, + localizationMap + ); } + } catch (error: any) { + console.log(error); + logger.error(error); + await enrichAndPersistCampaignWithError(request?.body, error); + } } async function processBasedOnAction(request: any, actionInUrl: any) { - if (actionInUrl == "create") { - request.body.CampaignDetails.id = uuidv4() - } - await enrichAndPersistProjectCampaignForFirst(request, actionInUrl, true) - processAfterPersist(request, actionInUrl) + if (actionInUrl == "create") { + request.body.CampaignDetails.id = uuidv4(); + } + await enrichAndPersistProjectCampaignForFirst(request, actionInUrl, true); + if ( + actionInUrl == "create" && + request.body?.parentCampaign && + request?.body?.CampaignDetails?.action === "draft" + ) { + callGenerateWhenChildCampaigngetsCreated(request); + } + processAfterPersist(request, actionInUrl); } - async function getLocalizedHierarchy(request: any, localizationMap: any) { - var hierarchy = await getHierarchy(request, request?.query?.tenantId, request?.query?.hierarchyType); - var modifiedHierarchy = hierarchy.map((ele) => - `${request?.query?.hierarchyType}_${ele}`.toUpperCase() + var hierarchy = await getHierarchy( + request, + request?.query?.tenantId, + request?.query?.hierarchyType + ); + var modifiedHierarchy = hierarchy.map((ele) => + `${request?.query?.hierarchyType}_${ele}`.toUpperCase() + ); + var resultHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); + return resultHierarchy; +} + +async function appendSheetsToWorkbook( + request: any, + boundaryData: any[], + differentTabsBasedOnLevel: any, + localizationMap?: any, + fileUrl?: any +) { + try { + logger.info( + "Received Boundary data for generating different tabs based on configured boundary level" ); - var resultHierarchy = getLocalizedHeaders( - modifiedHierarchy, - localizationMap + const hierarchy: any[] = await getLocalizedHierarchy( + request, + localizationMap ); - return resultHierarchy; -} - - -async function appendSheetsToWorkbook(request: any, boundaryData: any[], differentTabsBasedOnLevel: any, localizationMap?: any) { - try { - logger.info("Received Boundary data for generating different tabs based on configured boundary level"); - const hierarchy: any[] = await getLocalizedHierarchy(request, localizationMap); - const workbook = getNewExcelWorkbook(); - const type = request?.query?.type; - const headingInSheet = headingMapping?.[type]; - const localisedHeading = getLocalizedName(headingInSheet, localizationMap); - await createReadMeSheet(request, workbook, localisedHeading, localizationMap); - const [mainSheetData, uniqueDistrictsForMainSheet, districtLevelRowBoundaryCodeMap] = createBoundaryDataMainSheet(request, boundaryData, differentTabsBasedOnLevel, hierarchy, localizationMap) - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); - if (!(isSourceMicroplan)) { - const mainSheet = workbook.addWorksheet(getLocalizedName(getBoundaryTabName(), localizationMap)); - const columnWidths = Array(12).fill(30); - mainSheet.columns = columnWidths.map(width => ({ width })); - // mainSheetData.forEach(row => mainSheet.addRow(row)); - addDataToSheet(mainSheet, mainSheetData, 'F3842D', 30, false, true); - mainSheet.state = 'hidden'; - } - logger.info("appending different districts tab in the sheet started") - await appendDistricts(request, workbook, uniqueDistrictsForMainSheet, differentTabsBasedOnLevel, boundaryData, localizationMap, districtLevelRowBoundaryCodeMap, hierarchy, campaignObject); - logger.info("Sheet with different tabs generated successfully"); - return workbook; - } catch (error) { - console.log(error); - throw Error("An error occurred while creating tabs based on district:"); - } -} - - -async function appendDistricts(request: any, workbook: any, uniqueDistrictsForMainSheet: any, differentTabsBasedOnLevel: any, boundaryData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, hierarchy: any, campaignObject: any) { - const configurableColumnHeadersFromSchemaForTargetSheet = await getConfigurableColumnHeadersFromSchemaForTargetSheet(request, hierarchy, boundaryData, differentTabsBasedOnLevel, campaignObject, localizationMap); - for (const uniqueData of uniqueDistrictsForMainSheet) { - const uniqueDataFromLevelForDifferentTabs = uniqueData.slice(uniqueData.lastIndexOf('#') + 1); - logger.info(`generating the boundary data for ${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel}`) - const districtDataFiltered = boundaryData.filter((boundary: any) => boundary[differentTabsBasedOnLevel] === uniqueDataFromLevelForDifferentTabs && boundary[hierarchy[hierarchy.length - 1]]); - const modifiedFilteredData = modifyFilteredData(districtDataFiltered, districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap); - if (modifiedFilteredData?.[0]) { - const newSheetData = [configurableColumnHeadersFromSchemaForTargetSheet]; - for (const data of modifiedFilteredData) { - var rowData: any[] = []; - for (const header of configurableColumnHeadersFromSchemaForTargetSheet) { - rowData.push(data[header] || ''); - } - newSheetData.push(rowData); - } - await createNewSheet(request, workbook, newSheetData, uniqueData, localizationMap, districtLevelRowBoundaryCodeMap, configurableColumnHeadersFromSchemaForTargetSheet, campaignObject); - logger.info(`${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel} boundary data generation completed`) + const workbook = getNewExcelWorkbook(); + const type = request?.query?.type; + const headingInSheet = headingMapping?.[type]; + const localisedHeading = getLocalizedName(headingInSheet, localizationMap); + await createReadMeSheet( + request, + workbook, + localisedHeading, + localizationMap + ); + const [ + mainSheetData, + uniqueDistrictsForMainSheet, + districtLevelRowBoundaryCodeMap, + ] = createBoundaryDataMainSheet( + request, + boundaryData, + differentTabsBasedOnLevel, + hierarchy, + localizationMap + ); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + // const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + const mainSheet = workbook.addWorksheet( + getLocalizedName(getBoundaryTabName(), localizationMap) + ); + const columnWidths = Array(12).fill(30); + mainSheet.columns = columnWidths.map((width) => ({ width })); + // mainSheetData.forEach(row => mainSheet.addRow(row)); + addDataToSheet( + request, + mainSheet, + mainSheetData, + "F3842D", + 30, + false, + true + ); + mainSheet.state = "hidden"; + logger.info("appending different districts tab in the sheet started"); + await appendDistricts( + request, + workbook, + uniqueDistrictsForMainSheet, + differentTabsBasedOnLevel, + boundaryData, + localizationMap, + districtLevelRowBoundaryCodeMap, + hierarchy, + campaignObject, + fileUrl + ); + logger.info("Sheet with different tabs generated successfully"); + return workbook; + } catch (error) { + console.log(error); + throw Error("An error occurred while creating tabs based on district:"); + } +} + +async function appendDistricts( + request: any, + workbook: any, + uniqueDistrictsForMainSheet: any, + differentTabsBasedOnLevel: any, + boundaryData: any, + localizationMap: any, + districtLevelRowBoundaryCodeMap: any, + hierarchy: any, + campaignObject: any, + fileUrl?: any +) { + const configurableColumnHeadersFromSchemaForTargetSheet = + await getConfigurableColumnHeadersFromSchemaForTargetSheet( + request, + hierarchy, + boundaryData, + differentTabsBasedOnLevel, + campaignObject, + localizationMap + ); + let sheetNamesOfProcessedFile: any; + if (fileUrl) { + const processedWorkbook = await getTargetWorkbook(fileUrl, localizationMap); + sheetNamesOfProcessedFile = processedWorkbook.worksheets.map( + (sheet: any) => sheet.name + ); + } + for (const uniqueData of uniqueDistrictsForMainSheet) { + const uniqueDataFromLevelForDifferentTabs = uniqueData.slice( + uniqueData.lastIndexOf("#") + 1 + ); + logger.info( + `generating the boundary data for ${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel}` + ); + const districtDataFiltered = boundaryData.filter( + (boundary: any) => + boundary[differentTabsBasedOnLevel] === + uniqueDataFromLevelForDifferentTabs && + boundary[hierarchy[hierarchy.length - 1]] + ); + const modifiedFilteredData = modifyFilteredData( + districtDataFiltered, + districtLevelRowBoundaryCodeMap.get(uniqueData), + differentTabsBasedOnLevel, + localizationMap + ); + if (modifiedFilteredData?.[0]) { + const newSheetData = [configurableColumnHeadersFromSchemaForTargetSheet]; + for (const data of modifiedFilteredData) { + var rowData: any[] = []; + for (const header of configurableColumnHeadersFromSchemaForTargetSheet) { + rowData.push(data[header] || ""); } - } -} - -async function createNewSheet(request: any, workbook: any, newSheetData: any, uniqueData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, localizedHeaders: any, campaignObject: any) { - const newSheet = workbook.addWorksheet(getLocalizedName(districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap)); - addDataToSheet(newSheet, newSheetData, 'F3842D', 40); - let columnsNotToBeFreezed: any; - const boundaryCodeColumnIndex = localizedHeaders.findIndex((header: any) => header === getLocalizedName(config?.boundary?.boundaryCode, localizationMap)); - if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0) { - columnsNotToBeFreezed = localizedHeaders.slice(boundaryCodeColumnIndex + 1); - } - else { - const mdmsResponse = await getMdmsDataBasedOnCampaignType(request, localizationMap) - columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; - } - const localizedColumnsNotToBeFreezed = getLocalizedHeaders(columnsNotToBeFreezed, localizationMap); - lockTargetFields(newSheet, localizedColumnsNotToBeFreezed, boundaryCodeColumnIndex); -} - - - - - -function modifyFilteredData(districtDataFiltered: any, targetBoundaryCode: any, localizationMap?: any): any { - - // Step 2: Slice the boundary code up to the last underscore - const slicedBoundaryCode = targetBoundaryCode.slice(0, targetBoundaryCode.lastIndexOf('_') + 1); - - // Step 3: Filter the rows that contain the sliced boundary code - const modifiedFilteredData = districtDataFiltered.filter((row: any, index: any) => { - // Extract the boundary code from the current row - const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap); - const boundaryCode = row[localizedBoundaryCode]; - // Check if the boundary code starts with the sliced boundary code - return boundaryCode.startsWith(slicedBoundaryCode); + newSheetData.push(rowData); + } + + await createNewSheet( + request, + workbook, + newSheetData, + uniqueData, + localizationMap, + districtLevelRowBoundaryCodeMap, + configurableColumnHeadersFromSchemaForTargetSheet, + campaignObject, + sheetNamesOfProcessedFile, + fileUrl + ); + logger.info( + `${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel} boundary data generation completed` + ); + } + } +} + +async function createNewSheet( + request: any, + workbook: any, + newSheetData: any, + uniqueData: any, + localizationMap: any, + districtLevelRowBoundaryCodeMap: any, + localizedHeaders: any, + campaignObject: any, + sheetNamesOfProcessedFile: any, + fileUrl?: any +) { + const newSheet = workbook.addWorksheet( + getLocalizedName( + districtLevelRowBoundaryCodeMap.get(uniqueData), + localizationMap + ) + ); + let modifiedNewSheetData: any = newSheetData; + const oldTargetColumnsToHide: any[] = []; + if (fileUrl) { + let processedDistrictSheetData: any; + if ( + sheetNamesOfProcessedFile.includes( + getLocalizedName( + districtLevelRowBoundaryCodeMap.get(uniqueData), + localizationMap + ) + ) + ) { + processedDistrictSheetData = await getSheetData( + fileUrl, + getLocalizedName( + districtLevelRowBoundaryCodeMap.get(uniqueData), + localizationMap + ), + false, + undefined, + localizationMap + ); + } + modifiedNewSheetData = modifyNewSheetData( + processedDistrictSheetData, + newSheetData, + localizedHeaders, + oldTargetColumnsToHide, + localizationMap + ); + } + addDataToSheet(request, newSheet, modifiedNewSheetData, "F3842D", 40); + if (oldTargetColumnsToHide && oldTargetColumnsToHide.length > 0) { + const columnIndexesToBeHidden: any[] = []; + oldTargetColumnsToHide.forEach((column: any) => { + const localizedColumn = getLocalizedName(column, localizationMap); + const columnIndex = getColumnIndexByHeader(newSheet, localizedColumn); + columnIndexesToBeHidden.push(columnIndex); }); - // Step 4: Return the modified filtered data - return modifiedFilteredData; -} - -async function generateFilteredBoundaryData(request: any, FiltersFromCampaignId: any) { - const rootBoundary: any = (FiltersFromCampaignId?.Filters?.boundaries).filter((boundary: any) => boundary.isRoot); - const params = { - ...request?.query, - includeChildren: true, - codes: rootBoundary?.[0]?.code - }; - const boundaryDataFromRootOnwards = await getBoundaryRelationshipData(request, params); - logger.info(`filtering the boundaries`); - const filteredBoundaryList = filterBoundaries(boundaryDataFromRootOnwards, FiltersFromCampaignId?.Filters) - logger.info(`filtered the boundaries based on given criteria`) - return filteredBoundaryList; + hideColumnsOfProcessedFile(newSheet, columnIndexesToBeHidden); + } + let columnsNotToBeFreezed: any; + const boundaryCodeColumnIndex = localizedHeaders.findIndex( + (header: any) => + header === + getLocalizedName(config?.boundary?.boundaryCode, localizationMap) + ); + if ( + isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && + campaignObject.deliveryRules && + campaignObject.deliveryRules.length > 0 + ) { + columnsNotToBeFreezed = localizedHeaders.slice(boundaryCodeColumnIndex + 1); + } else { + const mdmsResponse = await getMdmsDataBasedOnCampaignType( + request, + localizationMap + ); + columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + } + const localizedColumnsNotToBeFreezed = getLocalizedHeaders( + columnsNotToBeFreezed, + localizationMap + ); + lockTargetFields( + newSheet, + localizedColumnsNotToBeFreezed, + boundaryCodeColumnIndex + ); +} + +function modifyFilteredData( + districtDataFiltered: any, + targetBoundaryCode: any, + differentTabsBasedOnLevel: any, + localizationMap?: any +): any { + // Retrieve the localized version of the target boundary code if a localization map is provided + const desiredBoundaryCode = getLocalizedName( + targetBoundaryCode, + localizationMap + ); + // Filter the district data to include only rows where the boundary code matches the desired one + const modifiedFilteredData = districtDataFiltered.filter((row: any) => { + return row[differentTabsBasedOnLevel] == desiredBoundaryCode; + }); + // Return the filtered data + return modifiedFilteredData; +} + +async function generateFilteredBoundaryData( + request: any, + FiltersFromCampaignId: any +) { + const rootBoundary: any = (FiltersFromCampaignId?.Filters?.boundaries).filter( + (boundary: any) => boundary.isRoot + ); + const params = { + ...request?.query, + includeChildren: true, + codes: rootBoundary?.[0]?.code, + }; + const boundaryDataFromRootOnwards = await getBoundaryRelationshipData( + request, + params + ); + logger.info(`filtering the boundaries`); + const filteredBoundaryList = filterBoundaries( + boundaryDataFromRootOnwards, + FiltersFromCampaignId?.Filters + ); + logger.info(`filtered the boundaries based on given criteria`); + return filteredBoundaryList; } function filterBoundaries(boundaryData: any[], filters: any): any { - function filterRecursive(boundary: any): any { - const boundaryFilters = filters && filters.boundaries; // Accessing boundaries array from filters object - const filter = boundaryFilters?.find((f: any) => f.code === boundary.code && f.boundaryType === boundary.boundaryType); - - if (!filter) { - return { - ...boundary, - children: boundary.children.map(filterRecursive) - }; - } - - if (!boundary.children.length) { - if (!filter.includeAllChildren) { - // throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary cannot have includeAllChildren filter false if it does not have any children"); - logger.error("Boundary cannot have includeAllChildren filter false if it does not have any children"); - } - // If boundary has no children and includeAllChildren is true, return as is - return { - ...boundary, - children: [] - }; - } - - if (filter.includeAllChildren) { - // If includeAllChildren is true, return boundary with all children - return { - ...boundary, - children: boundary.children.map(filterRecursive) - }; - } + function filterRecursive(boundary: any): any { + const boundaryFilters = filters && filters.boundaries; // Accessing boundaries array from filters object + const filter = boundaryFilters?.find( + (f: any) => + f.code === boundary.code && f.boundaryType === boundary.boundaryType + ); - const filteredChildren: any[] = []; - boundary.children.forEach((child: any) => { - const matchingFilter = boundaryFilters.find((f: any) => f.code === child.code && f.boundaryType === child.boundaryType); - if (matchingFilter) { - filteredChildren.push(filterRecursive(child)); - } - }); - return { - ...boundary, - children: filteredChildren - }; - } - const filteredData = boundaryData.map(filterRecursive); - return filteredData; + if (!filter) { + return { + ...boundary, + children: boundary.children.map(filterRecursive), + }; + } + + if (!boundary.children.length) { + if (!filter.includeAllChildren) { + // throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary cannot have includeAllChildren filter false if it does not have any children"); + logger.error( + "Boundary cannot have includeAllChildren filter false if it does not have any children" + ); + } + // If boundary has no children and includeAllChildren is true, return as is + return { + ...boundary, + children: [], + }; + } + + if (filter.includeAllChildren) { + // If includeAllChildren is true, return boundary with all children + return { + ...boundary, + children: boundary.children.map(filterRecursive), + }; + } + + const filteredChildren: any[] = []; + boundary.children.forEach((child: any) => { + const matchingFilter = boundaryFilters.find( + (f: any) => + f.code === child.code && f.boundaryType === child.boundaryType + ); + if (matchingFilter) { + filteredChildren.push(filterRecursive(child)); + } + }); + return { + ...boundary, + children: filteredChildren, + }; + } + const filteredData = boundaryData.map(filterRecursive); + return filteredData; } - function generateHierarchy(boundaries: any[]) { - // Create an object to store boundary types and their parents - const parentMap: any = {}; - - // Populate the object with boundary types and their parents - for (const boundary of boundaries) { - parentMap[boundary.boundaryType] = boundary.parentBoundaryType; - } - - // Traverse the hierarchy to generate the hierarchy list - const hierarchyList = []; - for (const boundaryType in parentMap) { - if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { - const parentBoundaryType = parentMap[boundaryType]; - if (parentBoundaryType === null) { - // This boundary type has no parent, add it to the hierarchy list - hierarchyList.push(boundaryType); - // Traverse its children recursively - traverseChildren(boundaryType, parentMap, hierarchyList); - } - } - } - return hierarchyList; + // Create an object to store boundary types and their parents + const parentMap: any = {}; + + // Populate the object with boundary types and their parents + for (const boundary of boundaries) { + parentMap[boundary.boundaryType] = boundary.parentBoundaryType; + } + + // Traverse the hierarchy to generate the hierarchy list + const hierarchyList = []; + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === null) { + // This boundary type has no parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } + } + return hierarchyList; } function traverseChildren(parent: any, parentMap: any, hierarchyList: any[]) { - for (const boundaryType in parentMap) { - if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { - const parentBoundaryType = parentMap[boundaryType]; - if (parentBoundaryType === parent) { - // This boundary type has the current parent, add it to the hierarchy list - hierarchyList.push(boundaryType); - // Traverse its children recursively - traverseChildren(boundaryType, parentMap, hierarchyList); - } - } + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === parent) { + // This boundary type has the current parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } } + } } -function createBoundaryMap(boundaries: any[], boundaryMap: Map): void { - for (const boundary of boundaries) { - boundaryMap.set(boundary.code, boundary.boundaryType); - if (boundary.children.length > 0) { - createBoundaryMap(boundary.children, boundaryMap); - } +function createBoundaryMap( + boundaries: any[], + boundaryMap: Map +): void { + for (const boundary of boundaries) { + boundaryMap.set(boundary.code, boundary.boundaryType); + if (boundary.children.length > 0) { + createBoundaryMap(boundary.children, boundaryMap); } + } } -async function boundaryBulkUpload(request: any, localizationMap?: any) { - try { - logger.info("Boundary Relationship Creation Starts"); - await autoGenerateBoundaryCodes(request, localizationMap); - await generateProcessedFileAndPersist(request); - } - catch (error: any) { - console.log(error) - await handleResouceDetailsError(request, error) - } -} - -const autoGenerateBoundaryCodes = async (request: any, localizationMap?: any) => { - const { hierarchyType, tenantId } = request?.body?.ResourceDetails || {}; - const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, "get"); - const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); - const boundaryData = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, localizedBoundaryTab, false, undefined, localizationMap); - const updatedBoundaryData = updateBoundaryData(boundaryData); - const hierarchy = await getHierarchy(request, tenantId, hierarchyType) || []; - const modifiedBoundaryData = modifyBoundaryDataHeaders(updatedBoundaryData, hierarchy, localizationMap); - const [withBoundaryCode, withoutBoundaryCode] = modifyBoundaryData(modifiedBoundaryData, localizationMap); - const { mappingMap, countMap } = getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode); - const childParentMap = getChildParentMap([...withBoundaryCode, ...withoutBoundaryCode]); - const boundaryMap = await getAutoGeneratedBoundaryCodesHandler(withoutBoundaryCode, childParentMap, mappingMap, countMap, request); - logger.info("Boundary Code Auto Generation Completed"); - await createBoundaryEntities(request, boundaryMap); - logger.info("waiting for 2 secs to persist the boundary entities before creating boundary relationship") - await new Promise(resolve => setTimeout(resolve, 2000)); - const modifiedChildParentMap = modifyChildParentMap(childParentMap, boundaryMap); - await createBoundaryRelationship(request, boundaryMap, modifiedChildParentMap); - const boundaryDataForSheet = addBoundaryCodeToData(withBoundaryCode, withoutBoundaryCode, boundaryMap); - logger.info("Initiated the localisation message creation for the uploaded boundary"); - transformAndCreateLocalisation(boundaryMap, request); - const modifiedHierarchy = hierarchy.map(ele => `${hierarchyType}_${ele}`.toUpperCase()) - const headers = [...modifiedHierarchy, config?.boundary?.boundaryCode]; - const data = prepareDataForExcel(boundaryDataForSheet, hierarchy, boundaryMap); - const localizedHeaders = getLocalizedHeaders(headers, localizationMap); - const boundarySheetData: any = await createExcelSheet(data, localizedHeaders); - const workbook = getNewExcelWorkbook(); - const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - addDataToSheet(boundarySheet, boundarySheetData); - const boundaryFileDetails: any = await createAndUploadFile(workbook, request); - request.body.ResourceDetails.processedFileStoreId = boundaryFileDetails?.[0]?.fileStoreId; -} - - - -function updateBoundaryData(boundaryData: any[]): any[] { - const map: Map = new Map(); - const count: Map = new Map(); - - boundaryData.forEach((row) => { - const keys = Object.keys(row); - keys.forEach((key, index) => { - if (index > 0) { - const element = row[key]; - const previousKey = keys[index - 1]; - const previousElement = row[keys[index - 1]]; - const previousElementKey = `${previousKey}:${previousElement}`; - const elementKey = `${key}:${element}`; - - if (!map.has(elementKey)) { - map.set(elementKey, previousElementKey); - count.set(elementKey, 1); - } else { - const currentCount = count.get(elementKey)!; - if (map.get(elementKey) !== previousElementKey) { - map.set(elementKey, previousElementKey); - count.set(elementKey, currentCount + 1); - } - const uniqueCount = count.get(elementKey)!; - const uniqueElement = (uniqueCount > 1) ? `${element}-${(uniqueCount - 1).toString().padStart(2, '0')}` : `${element}`; - row[key] = uniqueElement; - } - } - }); - }); - return boundaryData; +async function boundaryGeometryManagement(request: any, localizationMap: any) { + try { + logger.info("Boundary Relationship Creation Starts For Geometry Data"); + await autoGenerateBoundaryCodesForGeoJson(request, localizationMap); + } catch (error: any) { + console.log(error); + await handleResouceDetailsError(request, error); + } } -function modifyBoundaryDataHeaders(boundaryData: any[], hierarchy: any[], localizationMap?: any) { - const updatedData = boundaryData.map((obj: any) => { - const updatedObj: { [key: string]: string | undefined } = {}; // Updated object with modified keys - - let hierarchyIndex = 0; // Track the index of the hierarchy array - - for (const key in obj) { - if (key != getLocalizedName(config?.boundary?.boundaryCode, localizationMap)) { - if (Object.prototype.hasOwnProperty.call(obj, key)) { - const hierarchyKey = hierarchy[hierarchyIndex]; // Get the key from the hierarchy array - updatedObj[hierarchyKey] = obj[key]; // Map the key to the updated object - hierarchyIndex++; // Move to the next key in the hierarchy array - } - } - else { - updatedObj[key] = obj[key]; - } - } - +async function boundaryBulkUpload(request: any, localizationMap?: any) { + try { + logger.info("Boundary Relationship Creation Starts"); + await autoGenerateBoundaryCodes(request, localizationMap); + await generateProcessedFileAndPersist(request); + } catch (error: any) { + console.log(error); + await handleResouceDetailsError(request, error); + } +} + +function updateBoundaryDataForBoundaryManagement( + request: any, + boundaryData: any[], + localizationMap: any +): { updatedData: any[]; latLongData: [number, number][] } { + const latLongData: [number, number][] = []; + const latKey = getLocalizedName("HCM_ADMIN_CONSOLE_LAT", localizationMap); + const longKey = getLocalizedName("HCM_ADMIN_CONSOLE_LONG", localizationMap); + + boundaryData.forEach((row) => { + // Check if the row contains both latitude and longitude keys + if (latKey in row && longKey in row) { + // Push latitude and longitude to the latLongData array + latLongData.push([row[latKey], row[longKey]]); + + // Remove the latitude and longitude from the original row + delete row[latKey]; + delete row[longKey]; + } + }); + + // Return both the updated boundary data and latLongData + return { + updatedData: boundaryData, + latLongData, + }; +} + +async function autoGenerateBoundaryCodesForGeoJson( + request: any, + localizationMap?: any +) { + const { hierarchyType, tenantId } = request?.body?.ResourceDetails || {}; + // const type = request?.body?.ResourceDetails?.type; + const fileResponse = await httpRequest( + config.host.filestore + config.paths.filestore + "/url", + {}, + { tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, + "get" + ); + var boundaryData = await getDataFromGeoJson( + fileResponse?.fileStoreIds?.[0]?.url + ); + const hierarchy = + (await getHierarchy(request, tenantId, hierarchyType)) || []; + const dataFromGeoJson = getGeoJsonData(boundaryData, hierarchy); + const childParentMap = getChildParentMap(dataFromGeoJson); + const countMap = new Map<{ key: string; value: string }, number>(); + const mappingMap = new Map<{ key: string; value: string }, string>(); + const boundaryMap = await getAutoGeneratedBoundaryCodesHandler( + dataFromGeoJson, + childParentMap, + mappingMap, + countMap, + request + ); + logger.info("Boundary Code Auto Generation Completed"); + await createBoundaryEntities(request, boundaryMap); + logger.info( + "waiting for 2 secs to persist the boundary entities before creating boundary relationship" + ); + await new Promise((resolve) => setTimeout(resolve, 2000)); + const modifiedChildParentMap = modifyChildParentMap( + childParentMap, + boundaryMap + ); + await createBoundaryRelationship( + request, + boundaryMap, + modifiedChildParentMap + ); + const boundaryGeoJsonAfterProcessing = addBoundaryCodeToGeoJsonData( + boundaryData, + hierarchy, + boundaryMap + ); + logger.info( + "Initiated the localisation message creation for the uploaded boundary" + ); + transformAndCreateLocalisation(boundaryMap, request); + const boundaryFileDetails: any = await createAndUploadJsonFile( + boundaryGeoJsonAfterProcessing, + request + ); + await updateAndPersistResourceDetails( + request, + boundaryFileDetails, + boundaryData?.name + ); + logger.info("Boundary Relationship Creation Completed"); +} + +async function updateAndPersistResourceDetails( + request: any, + boundaryFileDetails: any, + name: any +) { + const fileStoreId = boundaryFileDetails[0]?.fileStoreId; + const getLatestResourceDetails = await getResourceDetails(request); - return updatedObj; + if (getLatestResourceDetails == null) { + request.body.ResourceDetails = { + ...request?.body?.ResourceDetails, + processedFileStoreId: fileStoreId, + status: + request.body.ResourceDetails.status != resourceDataStatuses.invalid + ? resourceDataStatuses.completed + : resourceDataStatuses.invalid, + auditDetails: { + ...request?.body?.ResourceDetails?.auditDetails, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + }, + additionalDetails: + { + ...request?.body?.ResourceDetails?.additionalDetails, + sheetErrors: request?.body?.additionalDetailsErrors, + source: + request?.body?.ResourceDetails?.additionalDetails?.source == + "microplan" + ? "microplan" + : null, + [name]: [fileStoreId], + }, + }; + } else { + request.body.ResourceDetails = { + ...getLatestResourceDetails, + processedFileStoreId: fileStoreId, + status: + getLatestResourceDetails.status != resourceDataStatuses.invalid + ? resourceDataStatuses.completed + : resourceDataStatuses.invalid, + auditDetails: { + ...getLatestResourceDetails.auditDetails, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + }, + additionalDetails: + { + ...getLatestResourceDetails.additionalDetails, + sheetErrors: request?.body?.additionalDetailsErrors, + source: + getLatestResourceDetails.additionalDetails?.source == "microplan" + ? "microplan" + : null, + }, + }; + let additionalDetails = request?.body?.ResourceDetails?.additionalDetails; + if (additionalDetails && additionalDetails[name]) { + additionalDetails[name].push(fileStoreId); + } else { + additionalDetails = { ...additionalDetails, [name]: [fileStoreId] }; + } + request.body.ResourceDetails.additionalDetails = additionalDetails; + } + + const persistMessage: any = { ResourceDetails: request.body.ResourceDetails }; + await produceModifiedMessages( + persistMessage, + config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC + ); + logger.info( + `ResourceDetails to persist : ${request.body.ResourceDetails.type}` + ); +} + +async function getResourceDetails(request: any) { + const { tenantId, type, hierarchyType } = + request?.body?.ResourceDetails || request?.query; + const resourceDetails = request?.body?.ResourceDetails; + + request.body.SearchCriteria = request.body.SearchCriteria || {}; + + request.body.SearchCriteria = { + tenantId: tenantId, + type: type, + hierarchyType: hierarchyType, + status: resourceDataStatuses.completed, + }; + + const response = await searchDataService(request); + request.body.ResourceDetails = resourceDetails; + if (response.length > 0) { + response.sort( + (a: any, b: any) => + b.auditDetails.lastModifiedTime - a.auditDetails.lastModifiedTime + ); + return response[0]; + } else { + return null; + } +} +const addBoundaryCodeToGeoJsonData = ( + boundaryData: any, + hiearchy: any, + boundaryMap: Map +) => { + // const objectMap = boundaryMap.forEach((value, key) => {return { key: key.value, value: value }); + // Create the updatedBoundaryMap using a Map + const updatedBoundaryMap = new Map(); + boundaryMap.forEach((value, key) => { + const newKey = key.key + "_" + key.value; // Concatenate key and value + updatedBoundaryMap.set(newKey, value); // Set in the updated map + }); + + // Iterate through the boundary data + boundaryData.features.forEach((feature: any) => { + // Extract the properties object from the feature + const properties = feature.properties; + + // Iterate through the hierarchy + hiearchy.forEach((h: string) => { + // Build the field name + const field = h.toLowerCase() + "_name"; + + // Check if the field exists in the properties object + if (properties[field]) { + const boundaryName = h + "_" + properties[field]; + // Assign the boundary code to the properties object + properties[config.boundary.boundaryCode] = + updatedBoundaryMap.get(boundaryName); // Use .get() to access the Map + } }); - return updatedData; -} - -function modifyChildParentMap(childParentMap: Map, boundaryMap: Map): Map { - const modifiedMap: Map = new Map(); + }); - // Iterate over each entry in childParentMap - childParentMap.forEach((value, key) => { - // Get the modified key and value from boundaryMap - const modifiedKey = findMapValue(boundaryMap, key) || null; - const modifiedValue = value ? findMapValue(boundaryMap, value) : null; - - // Set the modified key-value pair in modifiedMap - modifiedMap.set(modifiedKey, modifiedValue); + return boundaryData; +}; +const getGeoJsonData = (boundaryData: any, hiearchy: any) => { + var data: any = []; + boundaryData.features?.forEach((feature: any) => { + const properties = feature.properties; + var row: any = []; + hiearchy.forEach((h: string) => { + const field = h.toLowerCase() + "_name"; + if (properties[field]) { + const d = { + key: h, + value: properties[field], + }; + row.push(d); + } }); + data.push(row); + }); + return data; +}; - return modifiedMap; -} +const getDataFromGeoJson = async (url: string) => { + // Define headers for HTTP request + const headers = { + "Content-Type": "application/json", + Accept: "application/json", + }; + logger.info("loading for the file based on fileurl"); + // Make HTTP request to retrieve Excel file as arraybuffer + const responseFile = await httpRequest(url, null, {}, "get", "json", headers); + logger.info("received the file response"); + return responseFile; +}; +const autoGenerateBoundaryCodes = async ( + request: any, + localizationMap?: any +) => { + const { hierarchyType, tenantId } = request?.body?.ResourceDetails || {}; + const hierarchy = + (await getHierarchy(request, tenantId, hierarchyType)) || []; + const headersOfBoundarySheet = hierarchy.map( + (e) => `${hierarchyType.toUpperCase()}_${e.toUpperCase()}` + ); + const localizedHeadersOfBoundarySheet = getLocalizedHeaders( + headersOfBoundarySheet, + localizationMap + ); + const type = request?.body?.ResourceDetails?.type; + const fileResponse = await httpRequest( + config.host.filestore + config.paths.filestore + "/url", + {}, + { tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, + "get" + ); + const localizedBoundaryTab = getLocalizedName( + getBoundaryTabName(), + localizationMap + ); + var boundaryData = await getSheetData( + fileResponse?.fileStoreIds?.[0]?.url, + localizedBoundaryTab, + false, + undefined, + localizationMap + ); + var latLongData: any; + if (type === "boundaryManagement") { + validateBoundarySheetDataInCreateFlow( + boundaryData, + localizedHeadersOfBoundarySheet + ); + const result = await updateBoundaryDataForBoundaryManagement( + request, + boundaryData, + localizationMap + ); + latLongData = result.latLongData; + boundaryData = result.updatedData; + } + const updatedBoundaryData = updateBoundaryData(boundaryData, hierarchy); + const modifiedBoundaryData = modifyBoundaryDataHeaders( + updatedBoundaryData, + hierarchy, + localizationMap + ); + const [withBoundaryCode, withoutBoundaryCode] = modifyBoundaryData( + modifiedBoundaryData, + localizationMap + ); + const { mappingMap, countMap } = + getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode); + const childParentMap = getChildParentMap([ + ...withBoundaryCode, + ...withoutBoundaryCode, + ]); + const boundaryMap = await getAutoGeneratedBoundaryCodesHandler( + withoutBoundaryCode, + childParentMap, + mappingMap, + countMap, + request + ); + logger.info("Boundary Code Auto Generation Completed"); + await createBoundaryEntities(request, boundaryMap); + logger.info( + "waiting for 2 secs to persist the boundary entities before creating boundary relationship" + ); + await new Promise((resolve) => setTimeout(resolve, 2000)); + const modifiedChildParentMap = modifyChildParentMap( + childParentMap, + boundaryMap + ); + await createBoundaryRelationship( + request, + boundaryMap, + modifiedChildParentMap + ); + const boundaryDataForSheet = addBoundaryCodeToData( + withBoundaryCode, + withoutBoundaryCode, + boundaryMap + ); + logger.info( + "Initiated the localisation message creation for the uploaded boundary" + ); + await transformAndCreateLocalisation(boundaryMap, request); + const modifiedHierarchy = hierarchy.map((ele) => + `${hierarchyType}_${ele}`.toUpperCase() + ); + var headers = [...modifiedHierarchy, config?.boundary?.boundaryCode]; + const data = prepareDataForExcel( + boundaryDataForSheet, + hierarchy, + boundaryMap + ); + if (type === "boundaryManagement") { + headers = [ + ...headers, + getLocalizedName("HCM_ADMIN_CONSOLE_LAT", localizationMap), + getLocalizedName("HCM_ADMIN_CONSOLE_LONG", localizationMap), + ]; + data.forEach((row: any[], index: string | number) => { + if (latLongData.length > index) { + row.push(latLongData[index][0], latLongData[index][1]); + } + }); + } + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + const boundarySheetData: any = await createExcelSheet(data, localizedHeaders); + const workbook = getNewExcelWorkbook(); + const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); + addDataToSheet(request, boundarySheet, boundarySheetData, "93C47D", 40, true); + const boundaryFileDetails: any = await createAndUploadFile(workbook, request); + request.body.ResourceDetails.processedFileStoreId = + boundaryFileDetails?.[0]?.fileStoreId; +}; -async function convertSheetToDifferentTabs(request: any, boundaryData: any, differentTabsBasedOnLevel: any, localizationMap?: any) { - // create different tabs on the level of hierarchy we want to - const updatedWorkbook = await appendSheetsToWorkbook(request, boundaryData, differentTabsBasedOnLevel, localizationMap); - // upload the excel and generate file store id - const boundaryDetails = await createAndUploadFile(updatedWorkbook, request); - return boundaryDetails; +function updateBoundaryData(boundaryData: any[], hierarchy: any[]): any[] { + const map: Map = new Map(); + const count: Map = new Map(); + + boundaryData.forEach((row) => { + const keys = Object.keys(row).filter((key) => hierarchy.includes(key)); + keys.forEach((key, index) => { + if (index > 0) { + const element = row[key]; + const previousKey = keys[index - 1]; + const previousElement = row[keys[index - 1]]; + const previousElementKey = `${previousKey}:${previousElement}`; + const elementKey = `${key}:${element}`; + + if (!map.has(elementKey)) { + map.set(elementKey, previousElementKey); + count.set(elementKey, 1); + } else { + const currentCount = count.get(elementKey)!; + if (map.get(elementKey) !== previousElementKey) { + map.set(elementKey, previousElementKey); + count.set(elementKey, currentCount + 1); + } + const uniqueCount = count.get(elementKey)!; + const uniqueElement = + uniqueCount > 1 + ? `${element}-${(uniqueCount - 1).toString().padStart(2, "0")}` + : `${element}`; + row[key] = uniqueElement; + } + } + }); + }); + return boundaryData; } -async function getBoundaryDataAfterGeneration(result: any, request: any, localizationMap?: any) { - const fileStoreId = result[0].fileStoreId; - const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: request?.query?.tenantId, fileStoreIds: fileStoreId }, "get"); - if (!fileResponse?.fileStoreIds?.[0]?.url) { - throwError("FILE", 400, "INVALID_FILE"); +function modifyBoundaryDataHeaders( + boundaryData: any[], + hierarchy: any[], + localizationMap?: any +) { + const updatedData = boundaryData.map((obj: any) => { + const updatedObj: { [key: string]: string | undefined } = {}; // Updated object with modified keys + + let hierarchyIndex = 0; // Track the index of the hierarchy array + + for (const key in obj) { + if ( + key != getLocalizedName(config?.boundary?.boundaryCode, localizationMap) + ) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + const hierarchyKey = hierarchy[hierarchyIndex]; // Get the key from the hierarchy array + updatedObj[hierarchyKey] = obj[key]; // Map the key to the updated object + hierarchyIndex++; // Move to the next key in the hierarchy array + } + } else { + updatedObj[key] = obj[key]; + } } - const boundaryData = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, getBoundaryTabName(), false, undefined, localizationMap); - return boundaryData; -} -function getLocalizedName(expectedName: string, localizationMap?: { [key: string]: string }) { - if (!localizationMap || !(expectedName in localizationMap)) { - return expectedName; - } - const localizedName = localizationMap[expectedName]; - return localizedName; + return updatedObj; + }); + return updatedData; } -async function getTargetBoundariesRelatedToCampaignId(request: any, localizationMap?: any) { - let CampaignDetails: any; - if (request?.body?.ResourceDetails?.campaignId) { - const searchBody = { - RequestInfo: request?.body?.RequestInfo, - CampaignDetails: { - ids: [request?.body?.ResourceDetails?.campaignId], - tenantId: request?.body?.ResourceDetails?.tenantId - } - } - const req: any = replicateRequest(request, searchBody) - const response = await searchProjectTypeCampaignService(req) - if (response?.CampaignDetails?.[0]) { - CampaignDetails = response?.CampaignDetails?.[0] - await addBoundariesForData(request, CampaignDetails) - } - else { - throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while Validating sheet boundaries"); - } - } - return CampaignDetails?.boundaries; -} +function modifyChildParentMap( + childParentMap: Map, + boundaryMap: Map +): Map { + const modifiedMap: Map = new Map(); + // Iterate over each entry in childParentMap + childParentMap.forEach((value, key) => { + // Get the modified key and value from boundaryMap + const modifiedKey = findMapValue(boundaryMap, key) || null; + const modifiedValue = value ? findMapValue(boundaryMap, value) : null; -function getFiltersFromCampaignSearchResponse(responseFromCampaignSearch: any) { - const boundaries = responseFromCampaignSearch?.CampaignDetails?.[0]?.boundaries?.map((ele: any) => ({ ...ele, boundaryType: ele?.type })); - if (!boundaries) { - logger.info(`no boundaries found so considering the complete hierarchy`); - return { Filters: null }; - } - logger.info(`boundaries found for filtering`); - return { Filters: { boundaries: boundaries } } -}; + // Set the modified key-value pair in modifiedMap + modifiedMap.set(modifiedKey, modifiedValue); + }); + return modifiedMap; +} +async function convertSheetToDifferentTabs( + request: any, + boundaryData: any, + differentTabsBasedOnLevel: any, + localizationMap?: any, + fileUrl?: any +) { + // create different tabs on the level of hierarchy we want to + const updatedWorkbook = await appendSheetsToWorkbook( + request, + boundaryData, + differentTabsBasedOnLevel, + localizationMap, + fileUrl + ); + // upload the excel and generate file store id + const boundaryDetails = await createAndUploadFile(updatedWorkbook, request); + return boundaryDetails; +} + +async function getBoundaryDataAfterGeneration( + result: any, + request: any, + localizationMap?: any +) { + const fileStoreId = result[0].fileStoreId; + const fileResponse = await httpRequest( + config.host.filestore + config.paths.filestore + "/url", + {}, + { tenantId: request?.query?.tenantId, fileStoreIds: fileStoreId }, + "get" + ); + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 400, "INVALID_FILE"); + } + const boundaryData = await getSheetData( + fileResponse?.fileStoreIds?.[0]?.url, + getBoundaryTabName(), + false, + undefined, + localizationMap + ); + return boundaryData; +} + +function getLocalizedName( + expectedName: string, + localizationMap?: { [key: string]: string } +) { + if (!localizationMap || !(expectedName in localizationMap)) { + return expectedName; + } + const localizedName = localizationMap[expectedName]; + return localizedName; +} -const getConfigurableColumnHeadersBasedOnCampaignType = async (request: any, localizationMap?: any) => { - try { - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - let campaignType = campaignObject?.projectType; - const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); - campaignType = (isSourceMicroplan) ? `${config?.prefixForMicroplanCampaigns}-${campaignType}` : campaignType; - const mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) - if (!mdmsResponse || mdmsResponse?.columns.length === 0) { - logger.error(`Campaign Type ${campaignType} has not any columns configured in schema`) - throwError("COMMON", 400, "SCHEMA_ERROR", `Campaign Type ${campaignType} has not any columns configured in schema`); - } - // Extract columns from the response - const columnsForGivenCampaignId = mdmsResponse?.columns; - - // Get localized headers based on the column names - const headerColumnsAfterHierarchy = getLocalizedHeaders(columnsForGivenCampaignId, localizationMap); - if (!headerColumnsAfterHierarchy.includes(getLocalizedName(config.boundary.boundaryCode, localizationMap))) { - logger.error(`Column Headers of generated Boundary Template does not have ${getLocalizedName(config.boundary.boundaryCode, localizationMap)} column`) - throwError("COMMON", 400, "VALIDATION_ERROR", `Column Headers of generated Boundary Template does not have ${getLocalizedName(config.boundary.boundaryCode, localizationMap)} column`) - } - return headerColumnsAfterHierarchy; - } catch (error: any) { - console.log(error) - throwError("FILE", 400, "FETCHING_COLUMN_ERROR", "Error fetching column Headers From Schema (either boundary code column not found or given Campaign Type not found in schema) Check logs") +async function getTargetBoundariesRelatedToCampaignId( + request: any, + localizationMap?: any +) { + let CampaignDetailsNew: any; + if (request?.body?.ResourceDetails?.campaignId) { + // const searchBody = { + // RequestInfo: request?.body?.RequestInfo, + const CampaignDetails = { + ids: [request?.body?.ResourceDetails?.campaignId], + tenantId: request?.body?.ResourceDetails?.tenantId, + } + // const req: any = replicateRequest(request, searchBody); + const response = await searchProjectTypeCampaignService(CampaignDetails); + if (response?.CampaignDetails?.[0]) { + CampaignDetailsNew = response?.CampaignDetails?.[0]; + await addBoundariesForData(request, CampaignDetailsNew); + } else { + throwError( + "CAMPAIGN", + 400, + "CAMPAIGN_NOT_FOUND", + "Campaign not found while Validating sheet boundaries" + ); } - + } + return CampaignDetailsNew?.boundaries; } - -async function getFinalValidHeadersForTargetSheetAsPerCampaignType(request: any, hierarchy: any[], differentTabsBasedOnLevel: any, localizationMap?: any) { - const modifiedHierarchy = hierarchy.map(ele => `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase()); - const localizedHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); - const index = localizedHierarchy.indexOf(getLocalizedName(differentTabsBasedOnLevel, localizationMap)); - const expectedHeadersForTargetSheetUptoHierarchy = index !== -1 ? localizedHierarchy.slice(index) : throwError("COMMON", 400, "VALIDATION_ERROR", `${getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)} level not present in the hierarchy`); +async function getFiltersFromCampaignSearchResponse( + request: any, + responseFromCampaignSearch: any +) { + const boundaries = await getBoundariesFromCampaignSearchResponse( + request, + responseFromCampaignSearch?.CampaignDetails?.[0] + ); + const boundariesModified = boundaries?.map((ele: any) => ({ + ...ele, + boundaryType: ele?.type, + })); + if (!boundariesModified) { + logger.info(`no boundaries found so considering the complete hierarchy`); + return { Filters: null }; + } + logger.info(`boundaries found for filtering`); + return { Filters: { boundaries: boundariesModified } }; +} + +const getConfigurableColumnHeadersBasedOnCampaignType = async ( + request: any, + localizationMap?: any +) => { + try { const responseFromCampaignSearch = await getCampaignSearchResponse(request); const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - const columnFromSchemaOfTargetTemplate = await generateDynamicTargetHeaders(request, campaignObject, localizationMap); - const localizedcolumnFromSchemaOfTargetTemplate = getLocalizedHeaders(columnFromSchemaOfTargetTemplate, localizationMap) - const expectedHeadersForTargetSheet = [...expectedHeadersForTargetSheetUptoHierarchy, getLocalizedName(config?.boundary?.boundaryCode, localizationMap), ...localizedcolumnFromSchemaOfTargetTemplate]; - return expectedHeadersForTargetSheet; -} + let campaignType = campaignObject?.projectType; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + campaignType = isSourceMicroplan + ? `${config?.prefixForMicroplanCampaigns}-${campaignType}` + : campaignType; + const isUpdate = request?.body?.parentCampaignObject ? true : false; + const mdmsResponse = await callMdmsTypeSchema( + request, + request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, + isUpdate, + request?.query?.type || request?.body?.ResourceDetails?.type, + campaignType + ); + if (!mdmsResponse || mdmsResponse?.columns.length === 0) { + logger.error( + `Campaign Type ${campaignType} has not any columns configured in schema` + ); + throwError( + "COMMON", + 400, + "SCHEMA_ERROR", + `Campaign Type ${campaignType} has not any columns configured in schema` + ); + } + // Extract columns from the response + const columnsForGivenCampaignId = mdmsResponse?.columns; + + // Get localized headers based on the column names + const headerColumnsAfterHierarchy = getLocalizedHeaders( + columnsForGivenCampaignId, + localizationMap + ); + if ( + !headerColumnsAfterHierarchy.includes( + getLocalizedName(config.boundary.boundaryCode, localizationMap) + ) + ) { + logger.error( + `Column Headers of generated Boundary Template does not have ${getLocalizedName( + config.boundary.boundaryCode, + localizationMap + )} column` + ); + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `Column Headers of generated Boundary Template does not have ${getLocalizedName( + config.boundary.boundaryCode, + localizationMap + )} column` + ); + } + return headerColumnsAfterHierarchy; + } catch (error: any) { + console.log(error); + throwError( + "FILE", + 400, + "FETCHING_COLUMN_ERROR", + "Error fetching column Headers From Schema (either boundary code column not found or given Campaign Type not found in schema) Check logs" + ); + } +}; -async function getDifferentTabGeneratedBasedOnConfig(request: any, boundaryDataGeneratedBeforeDifferentTabSeparation: any, localizationMap?: any) { - var boundaryDataGeneratedAfterDifferentTabSeparation: any = boundaryDataGeneratedBeforeDifferentTabSeparation; - const boundaryData = await getBoundaryDataAfterGeneration(boundaryDataGeneratedBeforeDifferentTabSeparation, request, localizationMap); - let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request); - differentTabsBasedOnLevel = getLocalizedName(`${request?.query?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), localizationMap); - logger.info(`Boundaries are seperated based on hierarchy type ${differentTabsBasedOnLevel}`) - const isKeyOfThatTypePresent = boundaryData.some((data: any) => data.hasOwnProperty(differentTabsBasedOnLevel)); - const boundaryTypeOnWhichWeSplit = boundaryData.filter((data: any) => data[differentTabsBasedOnLevel]); - if (isKeyOfThatTypePresent && boundaryTypeOnWhichWeSplit.length >= parseInt(config?.boundary?.numberOfBoundaryDataOnWhichWeSplit)) { - logger.info(`sinces the conditions are matched boundaries are getting splitted into different tabs`) - boundaryDataGeneratedAfterDifferentTabSeparation = await convertSheetToDifferentTabs(request, boundaryData, differentTabsBasedOnLevel, localizationMap); - } - return boundaryDataGeneratedAfterDifferentTabSeparation; +async function getFinalValidHeadersForTargetSheetAsPerCampaignType( + request: any, + hierarchy: any[], + differentTabsBasedOnLevel: any, + localizationMap?: any +) { + const modifiedHierarchy = hierarchy.map((ele) => + `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase() + ); + const localizedHierarchy = getLocalizedHeaders( + modifiedHierarchy, + localizationMap + ); + const index = localizedHierarchy.indexOf( + getLocalizedName(differentTabsBasedOnLevel, localizationMap) + ); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + var expectedHeadersForTargetSheetUptoHierarchy: any; + if (isSourceMicroplan) { + expectedHeadersForTargetSheetUptoHierarchy = localizedHierarchy; + } else { + expectedHeadersForTargetSheetUptoHierarchy = + index !== -1 + ? localizedHierarchy.slice(index) + : throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `${differentTabsBasedOnLevel} level not present in the hierarchy` + ); + } + const columnFromSchemaOfTargetTemplate = await generateDynamicTargetHeaders( + request, + campaignObject, + localizationMap + ); + const localizedcolumnFromSchemaOfTargetTemplate = getLocalizedHeaders( + columnFromSchemaOfTargetTemplate, + localizationMap + ); + let updatedLocalizedcolumnFromSchemaOfTargetTemplate = + localizedcolumnFromSchemaOfTargetTemplate; + if (request?.body?.parentCampaignObject) { + updatedLocalizedcolumnFromSchemaOfTargetTemplate = + localizedcolumnFromSchemaOfTargetTemplate + .map((item: any) => `${item}(OLD)`) + .concat(localizedcolumnFromSchemaOfTargetTemplate); + } + const expectedHeadersForTargetSheet = [ + ...expectedHeadersForTargetSheetUptoHierarchy, + getLocalizedName(config?.boundary?.boundaryCode, localizationMap), + ...updatedLocalizedcolumnFromSchemaOfTargetTemplate, + ]; + return expectedHeadersForTargetSheet; +} + +async function getDifferentTabGeneratedBasedOnConfig( + request: any, + boundaryDataGeneratedBeforeDifferentTabSeparation: any, + localizationMap?: any, + fileUrl?: any +) { + var boundaryDataGeneratedAfterDifferentTabSeparation: any = + boundaryDataGeneratedBeforeDifferentTabSeparation; + const boundaryData = await getBoundaryDataAfterGeneration( + boundaryDataGeneratedBeforeDifferentTabSeparation, + request, + localizationMap + ); + let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit( + request, + request?.query?.tenantId + ); + differentTabsBasedOnLevel = getLocalizedName( + `${request?.query?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), + localizationMap + ); + logger.info( + `Boundaries are seperated based on hierarchy type ${differentTabsBasedOnLevel}` + ); + const isKeyOfThatTypePresent = boundaryData.some((data: any) => + data.hasOwnProperty(differentTabsBasedOnLevel) + ); + const boundaryTypeOnWhichWeSplit = boundaryData.filter( + (data: any) => data[differentTabsBasedOnLevel] + ); + if ( + isKeyOfThatTypePresent && + boundaryTypeOnWhichWeSplit.length >= + parseInt(config?.boundary?.numberOfBoundaryDataOnWhichWeSplit) + ) { + logger.info( + `sinces the conditions are matched boundaries are getting splitted into different tabs` + ); + boundaryDataGeneratedAfterDifferentTabSeparation = + await convertSheetToDifferentTabs( + request, + boundaryData, + differentTabsBasedOnLevel, + localizationMap, + fileUrl + ); + } + return boundaryDataGeneratedAfterDifferentTabSeparation; +} + +async function getBoundaryOnWhichWeSplit(request: any, tenantId: any) { + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const MdmsCriteria: any = { + tenantId: tenantId, + schemaCode: `${config.values.moduleName}.${config.masterNameForSplitBoundariesOn}`, + filters: { + hierarchy: responseFromCampaignSearch?.CampaignDetails?.[0].hierarchyType, + }, + }; + const mdmsResponse: any = await searchMDMSDataViaV2Api(MdmsCriteria); + if (!Array.isArray(mdmsResponse?.mdms) || mdmsResponse.mdms.length === 0) { + throwError("MDMS", 500, "MDMS_DATA_NOT_FOUND_ERROR", `${responseFromCampaignSearch?.CampaignDetails?.[0].hierarchyType} hierarchy not configured in mdms data + ${config.values.moduleName}.${config.masterNameForSplitBoundariesOn}`) + } + return mdmsResponse?.mdms?.[0]?.data?.splitBoundariesOn; } -async function getBoundaryOnWhichWeSplit(request: any) { - const mdmsResponse = await getMDMSV1Data(request, config?.values?.moduleName, config?.masterNameForSplitBoundariesOn, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId); - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const hierarchyTypeFromCampaignResponseObject = responseFromCampaignSearch?.CampaignDetails?.[0].hierarchyType; - return mdmsResponse.filter((item: any) => item.hierarchy == hierarchyTypeFromCampaignResponseObject).map((item: any) => item.splitBoundariesOn); +function checkIfSourceIsMicroplan(objectWithAdditionalDetails: any): boolean { + return objectWithAdditionalDetails?.additionalDetails?.source === "microplan"; +} + +function createIdRequests(employees: any[]): any[] { + if (employees && Array.isArray(employees) && employees.length > 0) { + const { tenantId } = employees[0]; // Assuming all employees have the same tenantId + return Array.from({ length: employees.length }, () => ({ + tenantId: tenantId, + idName: config?.values?.idgen?.idNameForUserNameGeneration, + idFormat: config?.values?.idgen?.formatForUserName, + })); + } else { + return []; + } +} + +async function createUniqueUserNameViaIdGen(request: any) { + const idgenurl = config?.host?.idGenHost + config?.paths?.idGen; + try { + // Make HTTP request to ID generation service + const result = await httpRequest( + idgenurl, + request?.body, + undefined, + undefined, + undefined, + undefined + ); + + // Return null if ID generation fails + return result; + } catch (error: any) { + // Log the error + logger.error(`Error during ID generation: ${error.message}`); + + // Throw a custom error + throwError( + "ID_GENERATION", + 500, + "ID_GENERATION_FAILED", + `Error occurred while generating ID: ${error.message}` + ); + } } +async function processFetchMicroPlan(request: any) { + try { + logger.info("Waiting for 1 second for templates to get generated..."); + await new Promise((resolve) => setTimeout(resolve, 1000)); -function checkIfSourceIsMicroplan(objectWithAdditionalDetails: any): boolean { - return objectWithAdditionalDetails?.additionalDetails?.source === 'microplan'; -} + logger.info("Started processing fetch microplan"); + const { tenantId } = request.body.MicroplanDetails; + const localizationMap = await getLocalizedMessagesHandler(request, tenantId); + const resources: any = request?.body?.CampaignDetails?.resources || []; + const filteredResources = resources.filter( + (obj: any) => obj?.filestoreId && obj?.resourceId + ); + logger.info(`Filtered resources with valid IDs: ${filteredResources?.length}`); + logger.debug(`Filtered resources: ${getFormattedStringForDebug(filteredResources)}`); + const fetchOperations: Promise[] = []; + // Add fetch operations conditionally + if (filteredResources.length === 0 || filteredResources.every((obj: any) => obj?.type !== "facility")) { + fetchOperations.push(fetchFacilityData(request, localizationMap)); + } + if (filteredResources.length === 0 || filteredResources.every((obj: any) => obj?.type !== "boundaryWithTarget")) { + fetchOperations.push(fetchTargetData(request, localizationMap)); + } + if (filteredResources.length === 0 || filteredResources.every((obj: any) => obj?.type !== "user")) { + fetchOperations.push(fetchUserData(request, localizationMap)); + } + // Run all fetch operations in parallel + await Promise.all(fetchOperations); + logger.info("Updating campaign object after successful fetch microplan..."); + await updateCampaignAfterSearch(request, "MICROPLAN_COMPLETED"); -export { - generateProcessedFileAndPersist, - convertToTypeData, - getChildParentMap, - addBoundaryCodeToData, - prepareDataForExcel, - extractCodesFromBoundaryRelationshipResponse, - searchProjectCampaignResourcData, - processDataSearchRequest, - getCodeMappingsOfExistingBoundaryCodes, - processBasedOnAction, - appendSheetsToWorkbook, - generateFilteredBoundaryData, - generateHierarchy, - createBoundaryMap, - autoGenerateBoundaryCodes, - convertSheetToDifferentTabs, - getBoundaryDataAfterGeneration, - boundaryBulkUpload, - enrichAndPersistCampaignWithError, - getLocalizedName, - reorderBoundaries, - reorderBoundariesOfDataAndValidate, - getTargetBoundariesRelatedToCampaignId, - getFiltersFromCampaignSearchResponse, - getConfigurableColumnHeadersBasedOnCampaignType, - getFinalValidHeadersForTargetSheetAsPerCampaignType, - getDifferentTabGeneratedBasedOnConfig, - checkIfSourceIsMicroplan, - getBoundaryOnWhichWeSplit + logger.info("Completed processing fetch microplan"); + } catch (error: any) { + logger.error(`Error during microplan fetch: ${error.message}`); + await updateCampaignAfterSearch(request, "MICROPLAN_FETCH_FAILED"); + } } + + +async function updateCampaignAfterSearch(request: any, source = "MICROPLAN_FETCHING") { + logger.info("search campaign with id ") + const { tenantId, campaignId } = request.body.MicroplanDetails; + const campaignDetails = { + tenantId: tenantId, + ids: [campaignId] + } + const searchedCampaignResponse = await searchProjectTypeCampaignService(campaignDetails) + const searchedCamapignObject = searchedCampaignResponse?.CampaignDetails; + if (Array.isArray(searchedCamapignObject) && searchedCamapignObject.length > 0) { + const newRequestBody = { + RequestInfo: request.body.RequestInfo, // Retain the original RequestInfo + CampaignDetails: searchedCamapignObject?.[0] // campaigndetails from search response + }; + const req: any = replicateRequest(request, newRequestBody) + logger.info("Updating the received campaign object, source & its key"); + if (!req.body.CampaignDetails.additionalDetails) { + req.body.CampaignDetails.additionalDetails = {}; + } + req.body.CampaignDetails.additionalDetails.activity = source; + (!req.body?.CampaignDetails?.additionalDetails?.["disease"]) && (req.body.CampaignDetails.additionalDetails["disease"] = "MALARIA"), + (!req.body?.CampaignDetails?.additionalDetails?.["beneficiaryType"]) && (req.body.CampaignDetails.additionalDetails["beneficiaryType"] = + "INDIVIDUAL"); + req.body.CampaignDetails.additionalDetails["key"] = 1; + logger.debug( + `updated object with new source , disease & beneficiarytype ${getFormattedStringForDebug(req.body.CampaignDetails)}` + ); + await updateProjectTypeCampaignService(req); + logger.info("Updated the received campaign object"); + } else { + throwError("CAMPAIGN", 500, "CAMPAIGN_SEARCH_ERROR", "Error in campaign search"); + } +} + +export { + generateProcessedFileAndPersist, + convertToTypeData, + getChildParentMap, + addBoundaryCodeToData, + prepareDataForExcel, + extractCodesFromBoundaryRelationshipResponse, + searchProjectCampaignResourcData, + processDataSearchRequest, + getCodeMappingsOfExistingBoundaryCodes, + processBasedOnAction, + appendSheetsToWorkbook, + generateFilteredBoundaryData, + generateHierarchy, + createBoundaryMap, + autoGenerateBoundaryCodes, + convertSheetToDifferentTabs, + getBoundaryDataAfterGeneration, + boundaryBulkUpload, + enrichAndPersistCampaignWithError, + getLocalizedName, + reorderBoundaries, + reorderBoundariesOfDataAndValidate, + getTargetBoundariesRelatedToCampaignId, + getFiltersFromCampaignSearchResponse, + getConfigurableColumnHeadersBasedOnCampaignType, + getFinalValidHeadersForTargetSheetAsPerCampaignType, + getDifferentTabGeneratedBasedOnConfig, + checkIfSourceIsMicroplan, + getBoundaryOnWhichWeSplit, + createIdRequests, + createUniqueUserNameViaIdGen, + getRootBoundaryCode, + boundaryGeometryManagement, + getResourceDetails, + enrichInnerCampaignDetails, + processFetchMicroPlan, + updateCampaignAfterSearch, + processBoundary, +}; diff --git a/health-services/project-factory/src/server/utils/excelUtils.ts b/health-services/project-factory/src/server/utils/excelUtils.ts index 8f7a0acc614..f640b3ddcd8 100644 --- a/health-services/project-factory/src/server/utils/excelUtils.ts +++ b/health-services/project-factory/src/server/utils/excelUtils.ts @@ -3,6 +3,9 @@ import { changeFirstRowColumnColour, throwError } from "./genericUtils"; import { httpRequest } from "./request"; import { logger } from "./logger"; import config from "../config"; +import { freezeUnfreezeColumnsForProcessedFile, getColumnIndexByHeader, hideColumnsOfProcessedFile } from "./onGoingCampaignUpdateUtils"; +import { getLocalizedName } from "./campaignUtils"; +import createAndSearch from "../config/createAndSearch"; /** * Function to create a new Excel workbook using the ExcelJS library * @returns {ExcelJS.Workbook} - A new Excel workbook object @@ -15,7 +18,7 @@ const getNewExcelWorkbook = () => { // Function to retrieve workbook from Excel file URL and sheet name const getExcelWorkbookFromFileURL = async ( fileUrl: string, - sheetName: string + sheetName?: string ) => { // Define headers for HTTP request const headers = { @@ -34,20 +37,23 @@ const getExcelWorkbookFromFileURL = async ( ); logger.info("received the file response"); - // Create a new workbook instance + const workbook = getNewExcelWorkbook(); await workbook.xlsx.load(responseFile); logger.info("workbook created based on the fileresponse"); - // Check if the specified sheet exists in the workbook - const worksheet = workbook.getWorksheet(sheetName); - if (sheetName && !worksheet) { - throwError( - "FILE", - 400, - "INVALID_SHEETNAME", - `Sheet with name "${sheetName}" is not present in the file.` - ); + + if (sheetName) { + // Check if the specified sheet exists in the workbook + const worksheet = workbook.getWorksheet(sheetName); + if (!worksheet) { + throwError( + "FILE", + 400, + "INVALID_SHEETNAME", + `Sheet with name "${sheetName}" is not present in the file.` + ); + } } // Return the workbook @@ -55,7 +61,7 @@ const getExcelWorkbookFromFileURL = async ( }; function updateFontNameToRoboto(worksheet: ExcelJS.Worksheet) { - worksheet.eachRow({ includeEmpty: true }, (row) => { + worksheet?.eachRow({ includeEmpty: true }, (row) => { row.eachCell({ includeEmpty: true }, (cell) => { // Preserve existing font properties const existingFont = cell.font || {}; @@ -96,7 +102,7 @@ function formatWorksheet(worksheet: any, datas: any, headerSet: any) { worksheet.getColumn(1).width = 130; logger.info(`Freezing the whole sheet ${worksheet.name}`); - worksheet.eachRow((row: any) => { + worksheet?.eachRow((row: any) => { row.eachCell((cell: any) => { cell.protection = { locked: true }; }); @@ -104,7 +110,7 @@ function formatWorksheet(worksheet: any, datas: any, headerSet: any) { worksheet.protect('passwordhere', { selectLockedCells: true }); } -function performUnfreezeCells(sheet: any) { +function performUnfreezeCells(sheet: any, localizationMap?: any, fileUrl?: any) { logger.info(`Unfreezing the sheet ${sheet.name}`); let lastFilledColumn = 1; @@ -128,7 +134,7 @@ function performUnfreezeCells(sheet: any) { function performFreezeWholeSheet(sheet: any) { logger.info(`Freezing the whole sheet ${sheet.name}`); - sheet.eachRow((row: any) => { + sheet?.eachRow((row: any) => { row.eachCell((cell: any) => { cell.protection = { locked: true }; }); @@ -137,20 +143,31 @@ function performFreezeWholeSheet(sheet: any) { } // Function to add data to the sheet -function addDataToSheet(sheet: any, sheetData: any, firstRowColor: string = '93C47D', columnWidth: number = 40, frozeCells: boolean = false, frozeWholeSheet: boolean = false) { +function addDataToSheet( + request: any, + sheet: any, + sheetData: any, + firstRowColor: string = '93C47D', + columnWidth: number = 40, + frozeCells: boolean = false, + frozeWholeSheet: boolean = false, + localizationMap?: any, + fileUrl?: any, + schema?: any +) { sheetData?.forEach((row: any, index: number) => { - const worksheetRow = sheet.addRow(row); + const worksheetRow = sheet.addRow(row); if (index === 0) { formatFirstRow(worksheetRow, sheet, firstRowColor, columnWidth, frozeCells); } else { formatOtherRows(worksheetRow, frozeCells); } }); - - finalizeSheet(sheet, frozeCells, frozeWholeSheet); + finalizeSheet(request, sheet, frozeCells, frozeWholeSheet, localizationMap, fileUrl, schema); } + // Function to format the first row function formatFirstRow(row: any, sheet: any, firstRowColor: string, columnWidth: number, frozeCells: boolean) { row.eachCell((cell: any, colNumber: number) => { @@ -199,13 +216,42 @@ function formatOtherRows(row: any, frozeCells: boolean) { } // Function to finalize the sheet settings -function finalizeSheet(sheet: any, frozeCells: boolean, frozeWholeSheet: boolean) { +function finalizeSheet(request: any, sheet: any, frozeCells: boolean, frozeWholeSheet: boolean, localizationMap?: any, fileUrl?: any, schema?: any) { + const type = (request?.query?.type || request?.body?.ResourceDetails?.type); + const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; + const createAndSearchConfig = createAndSearch[typeWithoutWith]; + const columnIndexesToBeFreezed: any = []; + const columnIndexesToBeHidden: any = []; if (frozeCells) { - performUnfreezeCells(sheet); + performUnfreezeCells(sheet, localizationMap, fileUrl); } if (frozeWholeSheet) { performFreezeWholeSheet(sheet); } + let columnsToBeFreezed: any[] = []; + let columnsToHide: any[] = []; + if (fileUrl) { + columnsToHide = ["HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD",...schema?.columnsToHide]; + columnsToHide.forEach((column: any) => { + const localizedColumn = getLocalizedName(column, localizationMap); + const columnIndex = getColumnIndexByHeader(sheet, localizedColumn); + columnIndexesToBeHidden.push(columnIndex); + }); + + columnsToBeFreezed = ["HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", ...schema?.columnsToBeFreezed] + columnsToBeFreezed.forEach((column: any) => { + const localizedColumn = getLocalizedName(column, localizationMap); + const columnIndex = getColumnIndexByHeader(sheet, localizedColumn); + columnIndexesToBeFreezed.push(columnIndex); + }); + const activeColumnWhichIsNotToBeFreezed = createAndSearchConfig?.activeColumnName; + const boundaryCodeMandatoryColumnWhichIsNotToBeFreezed = getLocalizedName(config?.boundary?.boundaryCodeMandatory, localizationMap); + const localizedActiveColumnWhichIsNotToBeFreezed = getLocalizedName(activeColumnWhichIsNotToBeFreezed, localizationMap); + const columnIndexOfActiveColumn = getColumnIndexByHeader(sheet, localizedActiveColumnWhichIsNotToBeFreezed); + const columnIndexOfBoundaryCodeMandatory = getColumnIndexByHeader(sheet, boundaryCodeMandatoryColumnWhichIsNotToBeFreezed); + freezeUnfreezeColumnsForProcessedFile(sheet, columnIndexesToBeFreezed, [columnIndexOfActiveColumn, columnIndexOfBoundaryCodeMandatory]); // Example columns to freeze and unfreeze + hideColumnsOfProcessedFile(sheet, columnIndexesToBeHidden); + } updateFontNameToRoboto(sheet); sheet.views = [{ state: 'frozen', ySplit: 1, zoomScale: 110 }]; } @@ -216,7 +262,7 @@ function finalizeSheet(sheet: any, frozeCells: boolean, frozeWholeSheet: boolean function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCodeColumnIndex: any) { // Make every cell locked by default - newSheet.eachRow((row: any) => { + newSheet?.eachRow((row: any) => { row.eachCell((cell: any) => { cell.protection = { locked: true }; }); @@ -232,7 +278,7 @@ function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCod const targetColumnNumber = headers.indexOf(header) + 1; // Excel columns are 1-based logger.info(`Header: ${header}, Target Column Index: ${targetColumnNumber}`); if (targetColumnNumber > -1) { - newSheet.eachRow((row: any, rowNumber: number) => { + newSheet?.eachRow((row: any, rowNumber: number) => { changeFirstRowColumnColour(newSheet, 'B6D7A8', targetColumnNumber); if (rowNumber === 1) return; @@ -259,4 +305,4 @@ function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCod } -export { getNewExcelWorkbook, getExcelWorkbookFromFileURL, formatWorksheet, addDataToSheet, lockTargetFields, updateFontNameToRoboto }; +export { getNewExcelWorkbook, getExcelWorkbookFromFileURL, formatWorksheet, addDataToSheet, lockTargetFields, updateFontNameToRoboto, formatFirstRow, formatOtherRows, finalizeSheet }; diff --git a/health-services/project-factory/src/server/utils/generateUtils.ts b/health-services/project-factory/src/server/utils/generateUtils.ts index a8a03e65d7c..83a2ec08ce1 100644 --- a/health-services/project-factory/src/server/utils/generateUtils.ts +++ b/health-services/project-factory/src/server/utils/generateUtils.ts @@ -1,6 +1,6 @@ import { getLocalizedMessagesHandler, processGenerate, replicateRequest, throwError } from "./genericUtils"; import _ from 'lodash'; -import { logger } from "./logger"; +import { getFormattedStringForDebug, logger } from "./logger"; import { getBoundarySheetData } from "../api/genericApis"; import { getLocalisationModuleName } from "./localisationUtils"; @@ -20,18 +20,26 @@ function areBoundariesSame(existingBoundaries: any, currentBoundaries: any) { const currentSetOfBoundaries = new Set(currentBoundaries.map((currboundary: any) => JSON.stringify(extractProperties(currboundary)))); return _.isEqual(existingSetOfBoundaries, currentSetOfBoundaries); } +function isCampaignTypeSame(request: any) { + const existingCampaignType = request?.body?.ExistingCampaignDetails?.projectType; + const currentCampaignType = request?.body?.CampaignDetails?.projectType; + return _.isEqual(existingCampaignType, currentCampaignType); +} -async function callGenerateIfBoundariesDiffer(request: any) { +async function callGenerateIfBoundariesOrCampaignTypeDiffer(request: any) { try { const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + const boundaries = request?.body?.boundariesCombined if (ExistingCampaignDetails) { - if (!areBoundariesSame(ExistingCampaignDetails?.boundaries, request?.body?.CampaignDetails?.boundaries)) { - logger.info("Boundaries differ, generating new resources"); + if (!areBoundariesSame(ExistingCampaignDetails?.boundaries, boundaries) || isSourceDifferent(request) || !isCampaignTypeSame(request)) { + logger.info("Boundaries or Campaign Type differ, generating new resources"); + // Apply 2-second timeout after the condition check + await new Promise(resolve => setTimeout(resolve, 2000)); const newRequestBody = { RequestInfo: request?.body?.RequestInfo, Filters: { - boundaries: request?.body?.CampaignDetails?.boundaries + boundaries: boundaries } }; @@ -42,7 +50,8 @@ async function callGenerateIfBoundariesDiffer(request: any) { hierarchyType: request?.body?.CampaignDetails?.hierarchyType, campaignId: request?.body?.CampaignDetails?.id }; - + logger.info(`generating new resources for the campaignId: ${request?.body?.CampaignDetails?.id}`); + logger.debug(`boundaries of the generate request : ${getFormattedStringForDebug(boundaries)}`) const newParamsBoundary = { ...query, ...params, type: "boundary" }; const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); await callGenerate(newRequestBoundary, "boundary"); @@ -62,6 +71,16 @@ async function callGenerateIfBoundariesDiffer(request: any) { } } +function isSourceDifferent(request: any){ + const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + const CampaignDetails = request?.body?.CampaignDetails; + + if(CampaignDetails.additionalDetails.source !== ExistingCampaignDetails.additionalDetails.source){ + return true; + } + return false; +} + async function callGenerate(request: any, type: any, enableCaching = false) { logger.info(`calling generate api for type ${type}`); if (type === "facilityWithBoundary" || type == "userWithBoundary") { @@ -82,4 +101,4 @@ async function callGenerate(request: any, type: any, enableCaching = false) { -export { callGenerateIfBoundariesDiffer, callGenerate, areBoundariesSame } +export { callGenerateIfBoundariesOrCampaignTypeDiffer, callGenerate, areBoundariesSame } diff --git a/health-services/project-factory/src/server/utils/genericUtils.ts b/health-services/project-factory/src/server/utils/genericUtils.ts index df6f5ec8bfb..da91f18f0a9 100644 --- a/health-services/project-factory/src/server/utils/genericUtils.ts +++ b/health-services/project-factory/src/server/utils/genericUtils.ts @@ -4,7 +4,7 @@ import config, { getErrorCodes } from "../config/index"; import { v4 as uuidv4 } from 'uuid'; import { produceModifiedMessages } from "../kafka/Producer"; import { generateHierarchyList, getAllFacilities, getCampaignSearchResponse, getHierarchy } from "../api/campaignApis"; -import { getBoundarySheetData, getSheetData, createAndUploadFile, createExcelSheet, getTargetSheetData, callMdmsData, callMdmsTypeSchema } from "../api/genericApis"; +import { getBoundarySheetData, getSheetData, createAndUploadFile, createExcelSheet, getTargetSheetData, callMdmsData, callMdmsTypeSchema, getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement } from "../api/genericApis"; import { logger } from "./logger"; import { checkIfSourceIsMicroplan, getConfigurableColumnHeadersBasedOnCampaignType, getDifferentTabGeneratedBasedOnConfig, getLocalizedName } from "./campaignUtils"; import Localisation from "../controllers/localisationController/localisation.controller"; @@ -12,11 +12,13 @@ import { executeQuery } from "./db"; import { generatedResourceTransformer } from "./transforms/searchResponseConstructor"; import { generatedResourceStatuses, headingMapping, resourceDataStatuses } from "../config/constants"; import { getLocaleFromRequest, getLocaleFromRequestInfo, getLocalisationModuleName } from "./localisationUtils"; -import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; -import { getBoundaryDataService } from "../service/dataManageService"; +import { getBoundaryColumnName, getBoundaryTabName, getLatLongMapForBoundaryCodes } from "./boundaryUtils"; +import { getBoundaryDataService, searchDataService } from "../service/dataManageService"; import { addDataToSheet, formatWorksheet, getNewExcelWorkbook, updateFontNameToRoboto } from "./excelUtils"; import createAndSearch from "../config/createAndSearch"; import { generateDynamicTargetHeaders } from "./targetUtils"; +import { buildSearchCriteria, checkAndGiveIfParentCampaignAvailable, fetchFileUrls, getCreatedResourceIds, modifyProcessedSheetData } from "./onGoingCampaignUpdateUtils"; +import { getReadMeConfigForMicroplan, getRolesForMicroplan, getUserDataFromMicroplanSheet, isMicroplanRequest, modifyBoundaryIfSourceMicroplan } from "./microplanUtils"; const NodeCache = require("node-cache"); const updateGeneratedResourceTopic = config?.kafka?.KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC; @@ -371,14 +373,33 @@ async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResour const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; + let fileUrlResponse: any; + if(type != 'boundaryManagement' && request?.query?.campaignId != 'default' && type != 'boundaryGeometryManagement'){ + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + logger.info(`checks for parent campaign for type: ${type}`) + await checkAndGiveIfParentCampaignAvailable(request, campaignObject); + } + if (request?.body?.parentCampaignObject) { + const resourcesOfParentCampaign = request?.body?.parentCampaignObject?.resources; + const createdResourceId = getCreatedResourceIds(resourcesOfParentCampaign, type); + logger.info(` found createdResourceId as ${createdResourceId} `); + const searchCriteria = buildSearchCriteria(request, createdResourceId, type); + const responseFromDataSearch = await searchDataService(replicateRequest(request, searchCriteria)); + + const processedFileStoreIdForUSerOrFacility = responseFromDataSearch?.[0]?.processedFilestoreId; + fileUrlResponse = await fetchFileUrls(request, processedFileStoreIdForUSerOrFacility); + + } if (type === 'boundary') { // get boundary data from boundary relationship search api logger.info("Generating Boundary Data") const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request, enableCaching); logger.info(`Boundary data generated successfully: ${JSON.stringify(boundaryDataSheetGeneratedBeforeDifferentTabSeparation)}`); // get boundary sheet data after being generated + var boundaryDataSheetGeneratedAfterDifferentTabSeparation = boundaryDataSheetGeneratedBeforeDifferentTabSeparation; logger.info("generating different tabs logic ") - const boundaryDataSheetGeneratedAfterDifferentTabSeparation = await getDifferentTabGeneratedBasedOnConfig(request, boundaryDataSheetGeneratedBeforeDifferentTabSeparation, localizationMap) + boundaryDataSheetGeneratedAfterDifferentTabSeparation = await getDifferentTabGeneratedBasedOnConfig(request, boundaryDataSheetGeneratedBeforeDifferentTabSeparation, localizationMap, fileUrlResponse?.fileStoreIds?.[0]?.url) logger.info(`Different tabs based on level configured generated, ${JSON.stringify(boundaryDataSheetGeneratedAfterDifferentTabSeparation)}`) const finalResponse = await getFinalUpdatedResponse(boundaryDataSheetGeneratedAfterDifferentTabSeparation, newEntryResponse, request); const generatedResourceNew: any = { generatedResource: finalResponse } @@ -386,14 +407,28 @@ async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResour await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); request.body.generatedResource = finalResponse; } + else if (type == 'boundaryManagement' || type === 'boundaryGeometryManagement'){ + // get boundary data from boundary relationship search api + logger.info("Generating Boundary Data") + const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request, false); + logger.info(`Boundary data generated successfully: ${JSON.stringify(boundaryDataSheetGeneratedBeforeDifferentTabSeparation)}`); + // get boundary sheet data after being generated + const finalResponse = await getFinalUpdatedResponse(boundaryDataSheetGeneratedBeforeDifferentTabSeparation, newEntryResponse, request); + const generatedResourceNew: any = { generatedResource: finalResponse } + // send to update topic + await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + request.body.generatedResource = finalResponse; + logger.info("generation completed for boundary management create flow") + } else if (type == "facilityWithBoundary" || type == 'userWithBoundary') { - await processGenerateRequest(request, localizationMap, filteredBoundary); + await processGenerateRequest(request, localizationMap, filteredBoundary, fileUrlResponse?.fileStoreIds?.[0]?.url); const finalResponse = await getFinalUpdatedResponse(request?.body?.fileDetails, newEntryResponse, request); const generatedResourceNew: any = { generatedResource: finalResponse } await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); request.body.generatedResource = finalResponse; } - } catch (error: any) { + } + catch (error: any) { console.log(error) await handleGenerateError(newEntryResponse, generatedResource, error); } @@ -460,20 +495,61 @@ function setDropdownFromSchema(request: any, schema: any, localizationMap?: { [k }, {}); logger.info(`dropdowns to set ${JSON.stringify(dropdowns)}`) request.body.dropdowns = dropdowns; + return dropdowns; } -async function createFacilitySheet(request: any, allFacilities: any[], localizationMap?: { [key: string]: string }) { +function setHiddenColumns(request: any, schema: any, localizationMap?: { [key: string]: string }) { + // from schema.properties find the key whose value have value.hideColumn == true + const hiddenColumns = Object.entries(schema.properties).filter(([key, value]: any) => value.hideColumn == true).map(([key, value]: any) => getLocalizedName(key, localizationMap)); + logger.info(`Columns to hide ${JSON.stringify(hiddenColumns)}`); + request.body.hiddenColumns = hiddenColumns; +} + +async function getResourceDistributionStrategyTypes(request: any) { + const { RequestInfo = {} } = request?.body || {}; + const requestBody = { + RequestInfo, + MdmsCriteria: { + tenantId: request?.query?.tenantId, + schemaCode: "hcm-microplanning.ResourceDistributionStrategy" + } + }; + const url = config.host.mdmsV2 + config.paths.mdms_v2_search; + const response = await httpRequest(url, requestBody, undefined, undefined, undefined); + if (response?.mdms && Array.isArray(response?.mdms)) { + const resourceDistributionStrategyTypes = response?.mdms?.map((mdms: any) => mdms?.data?.resourceDistributionStrategyCode); + return resourceDistributionStrategyTypes; + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during resource distribution strategy type search"); + } +} + +async function getSchemaBasedOnSource(request: any, isSourceMicroplan: boolean, resourceDistributionStrategy: string) { const tenantId = request?.query?.tenantId; - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const isSourceMicroplan = checkIfSourceIsMicroplan(responseFromCampaignSearch?.CampaignDetails?.[0]); - let schema; + let schema: any; if (isSourceMicroplan) { - schema = await callMdmsTypeSchema(request, tenantId, "facility", "microplan"); + const resourceDistributionStrategyTypes = await getResourceDistributionStrategyTypes(request); + if (resourceDistributionStrategyTypes.includes(resourceDistributionStrategy)) { + schema = await callMdmsTypeSchema(request, tenantId, false, "facility", `MP-FACILITY-${resourceDistributionStrategy}`); + } + else { + throwError("CAMPAIGN", 500, "INVALID_RESOURCE_DISTRIBUTION_STRATEGY", `Invalid resource distribution strategy: ${resourceDistributionStrategy} ; Allowed resource distribution strategies: ${resourceDistributionStrategyTypes}`); + } } else { - schema = await callMdmsTypeSchema(request, tenantId, "facility", "all"); + schema = await callMdmsTypeSchema(request, tenantId, false, "facility", "all"); } + return schema; +} + +async function createFacilitySheet(request: any, allFacilities: any[], localizationMap?: { [key: string]: string }) { + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const isSourceMicroplan = checkIfSourceIsMicroplan(responseFromCampaignSearch?.CampaignDetails?.[0]); + request.body.isSourceMicroplan = isSourceMicroplan; + let schema: any = await getSchemaBasedOnSource(request, isSourceMicroplan, responseFromCampaignSearch?.CampaignDetails?.[0]?.additionalDetails?.resourceDistributionStrategy); const keys = schema?.columns; setDropdownFromSchema(request, schema, localizationMap); + setHiddenColumns(request, schema, localizationMap); const headers = ["HCM_ADMIN_CONSOLE_FACILITY_CODE", ...keys] let localizedHeaders; if (isSourceMicroplan) { @@ -523,10 +599,15 @@ function setAndFormatHeaders(worksheet: any, mainHeader: any, headerSet: any) { } async function createReadMeSheet(request: any, workbook: any, mainHeader: any, localizationMap = {}) { - const readMeConfig = await getReadMeConfig(request); + const isSourceMicroplan = await isMicroplanRequest(request); + let readMeConfig: any; + if(isSourceMicroplan) { + readMeConfig = await getReadMeConfigForMicroplan(request); + } + else{ + readMeConfig = await getReadMeConfig(request); + } const headerSet = new Set(); - - const datas = readMeConfig.texts .filter((text: any) => text?.inSheet) // Filter out texts with inSheet set to false .flatMap((text: any) => { @@ -650,7 +731,7 @@ function hideUniqueIdentifierColumn(sheet: any, column: any) { } -async function createFacilityAndBoundaryFile(facilitySheetData: any, boundarySheetData: any, request: any, localizationMap?: any) { +async function createFacilityAndBoundaryFile(facilitySheetData: any, boundarySheetData: any, request: any, localizationMap?: any, fileUrl?: any, schema?: any) { const workbook = getNewExcelWorkbook(); // Add facility sheet to the workbook @@ -664,63 +745,99 @@ async function createFacilityAndBoundaryFile(facilitySheetData: any, boundaryShe // Add facility sheet data const facilitySheet = workbook.addWorksheet(localizedFacilityTab); - addDataToSheet(facilitySheet, facilitySheetData, undefined, undefined, true); + addDataToSheet(request, facilitySheet, facilitySheetData, undefined, undefined, true, false, localizationMap, fileUrl, schema); hideUniqueIdentifierColumn(facilitySheet, createAndSearch?.["facility"]?.uniqueIdentifierColumn); changeFirstRowColumnColour(facilitySheet, 'E06666'); - await handledropdownthings(facilitySheet, request.body?.dropdowns); + + let receivedDropdowns=request.body?.dropdowns; + logger.info("started adding dropdowns in facility",JSON.stringify(receivedDropdowns)) + + if(!receivedDropdowns||Object.keys(receivedDropdowns)?.length==0){ + logger.info("No dropdowns found"); + receivedDropdowns= setDropdownFromSchema(request,schema,localizationMap); + logger.info("refetched drodowns",JSON.stringify(receivedDropdowns)) + } + await handledropdownthings(facilitySheet, receivedDropdowns); + await handleHiddenColumns(facilitySheet, request.body?.hiddenColumns); // Add boundary sheet to the workbook const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - addDataToSheet(boundarySheet, boundarySheetData, 'F3842D', 30, false, true); + boundarySheetData = modifyBoundaryIfSourceMicroplan(boundarySheetData, request); + addDataToSheet(request, boundarySheet, boundarySheetData, 'F3842D', 30, false, true); // Create and upload the fileData at row const fileDetails = await createAndUploadFile(workbook, request); request.body.fileDetails = fileDetails; } -async function handledropdownthings(facilitySheet: any, dropdowns: any) { +async function handledropdownthings(sheet: any, dropdowns: any) { let dropdownColumnIndex = -1; if (dropdowns) { + logger.info("Dropdowns provided:", dropdowns); for (const key of Object.keys(dropdowns)) { if (dropdowns[key]) { - // Iterate through each row to find the column index of "Boundary Code (Mandatory)" - await facilitySheet.eachRow({ includeEmpty: true }, (row: any) => { - row.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { - if (cell.value === key) { - dropdownColumnIndex = colNumber; - } - }); + logger.info(`Processing dropdown key: ${key} with values: ${dropdowns[key]}`); + const firstRow = sheet.getRow(1); + firstRow.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { + if (cell.value === key) { + dropdownColumnIndex = colNumber; + logger.info(`Found column index for dropdown "${key}": ${dropdownColumnIndex}`); + } }); // If dropdown column index is found, set multi-select dropdown for subsequent rows if (dropdownColumnIndex !== -1) { - facilitySheet.getColumn(dropdownColumnIndex).eachCell({ includeEmpty: true }, (cell: any, rowNumber: any) => { + logger.info(`Setting dropdown for column index: ${dropdownColumnIndex}`); + sheet.getColumn(dropdownColumnIndex).eachCell({ includeEmpty: true }, (cell: any, rowNumber: any) => { if (rowNumber > 1) { // Set dropdown list with no typing allowed cell.dataValidation = { type: 'list', formulae: [`"${dropdowns[key].join(',')}"`], - showDropDown: true, // Ensures dropdown is visible + showDropDown: true, error: 'Please select a value from the dropdown list.', - errorStyle: 'stop', // Prevents any input not in the list - showErrorMessage: true, // Ensures error message is shown + errorStyle: 'stop', + showErrorMessage: true, errorTitle: 'Invalid Entry' }; } }); + } else { + logger.info(`Dropdown column index not found for key: ${key}`); } } } + } else { + logger.info("No dropdowns provided."); } } +async function handleHiddenColumns(sheet: any, hiddenColumns: any) { + // logger.info(sheet) + logger.info("hiddenColumns",hiddenColumns); + if (hiddenColumns) { + for (const columnName of hiddenColumns) { + const firstRow = sheet.getRow(1); + let colIndex = -1; + firstRow.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { + if (cell.value === columnName) { + colIndex = colNumber; + } + if (colIndex !== -1) { + sheet.getColumn(colIndex).hidden = true + } + }); + } + } +} -async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: any, request: any, localizationMap?: { [key: string]: string }) { + +async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: any, request: any, schema: any, localizationMap?: { [key: string]: string }, fileUrl?: any) { const workbook = getNewExcelWorkbook(); const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); const type = request?.query?.type; @@ -729,64 +846,222 @@ async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: await createReadMeSheet(request, workbook, localisedHeading, localizationMap); const userSheet = workbook.addWorksheet(localizedUserTab); - addDataToSheet(userSheet, userSheetData, undefined, undefined, true); - await handledropdownthings(userSheet, request.body?.dropdowns); + addDataToSheet(request, userSheet, userSheetData, undefined, undefined, true, false, localizationMap, fileUrl, schema); + hideUniqueIdentifierColumn(userSheet, createAndSearch?.["user"]?.uniqueIdentifierColumn); + + let receivedDropdowns=request.body?.dropdowns; + logger.info("started adding dropdowns in user",JSON.stringify(receivedDropdowns)) + + if(!receivedDropdowns||Object.keys(receivedDropdowns)?.length==0){ + logger.info("No dropdowns found"); + receivedDropdowns= setDropdownFromSchema(request,schema,localizationMap); + logger.info("refetched drodowns",JSON.stringify(receivedDropdowns)) + } + await handledropdownthings(userSheet, receivedDropdowns); + await handleHiddenColumns(userSheet, request.body?.hiddenColumns); // Add boundary sheet to the workbook const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap) const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - addDataToSheet(boundarySheet, boundarySheetData, 'F3842D', 30, false, true); + addDataToSheet(request, boundarySheet, boundarySheetData, 'F3842D', 30, false, true); const fileDetails = await createAndUploadFile(workbook, request) request.body.fileDetails = fileDetails; } -async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { +async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, fileUrl?: any) { // Get facility and boundary data logger.info("Generating facilities started"); const allFacilities = await getAllFacilities(tenantId, request.body); request.body.generatedResourceCount = allFacilities?.length; logger.info(`Facilities generation completed and found ${allFacilities?.length} facilities`); - const facilitySheetData: any = await createFacilitySheet(request, allFacilities, localizationMap); + let facilitySheetData: any; + const localizedFacilityTab = getLocalizedName(config?.facility?.facilityTab, localizationMap); + let schema: any; + if (fileUrl) { + /* fetch facility from processed file + and generate facility sheet data */ + const processedFacilitySheetData = await getSheetData(fileUrl, localizedFacilityTab, false, undefined, localizationMap); + const modifiedProcessedFacilitySheetData = modifyProcessedSheetData(request, processedFacilitySheetData, localizationMap); + facilitySheetData = modifiedProcessedFacilitySheetData; + schema = await callMdmsTypeSchema(request, tenantId, true, "facility", "all"); + setDropdownFromSchema(request, schema, localizationMap); + } + else { + facilitySheetData = await createFacilitySheet(request, allFacilities, localizationMap); + } // request.body.Filters = { tenantId: tenantId, hierarchyType: request?.query?.hierarchyType, includeChildren: true } if (filteredBoundary && filteredBoundary.length > 0) { - await createFacilityAndBoundaryFile(facilitySheetData, filteredBoundary, request, localizationMap); + logger.info("proceed with the filtered boundary data") + await createFacilityAndBoundaryFile(facilitySheetData, filteredBoundary, request, localizationMap, fileUrl, schema); } else { const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); - await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap); + await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap, fileUrl, schema); } } -async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { - const userData: any[] = []; + +async function generateUserSheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, userData?: any, fileUrl?: any) { const tenantId = request?.query?.tenantId; - const schema = await callMdmsTypeSchema(request, tenantId, "user"); + let schema: any; + const isUpdate = fileUrl ? true : false; + schema = await callMdmsTypeSchema(request, tenantId, isUpdate, "user"); setDropdownFromSchema(request, schema, localizationMap); const headers = schema?.columns; const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); + let userSheetData: any; // const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); logger.info("Generated an empty user template"); - const userSheetData = await createExcelSheet(userData, localizedHeaders); + if (fileUrl) { + /* fetch facility from processed file + and generate facility sheet data */ + const processedUserSheetData = await getSheetData(fileUrl, localizedUserTab, false, undefined, localizationMap); + const modifiedProcessedUserSheetData = modifyProcessedSheetData(request, processedUserSheetData, localizationMap); + userSheetData = modifiedProcessedUserSheetData; + } + else { + userSheetData = await createExcelSheet(userData, localizedHeaders); + } if (filteredBoundary && filteredBoundary.length > 0) { - await createUserAndBoundaryFile(userSheetData, filteredBoundary, request, localizationMap); + logger.info("proceed with the filtered boundary data") + await createUserAndBoundaryFile(userSheetData, filteredBoundary, request, schema, localizationMap, fileUrl); } else { const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); - await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, localizationMap); + await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, schema, localizationMap, fileUrl); } } -async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { + + +async function getCustomSheetData(request: any, type: any, sheetName: any) { + const { RequestInfo = {} } = request?.body || {}; + const requestBody = { + RequestInfo, + MdmsCriteria: { + tenantId: request?.query?.tenantId, + uniqueIdentifiers: [ + `${sheetName}.${type}` + ], + schemaCode: "HCM-ADMIN-CONSOLE.customSheetData" + } + }; + const url = config.host.mdmsV2 + config.paths.mdms_v2_search; + const header = { + ...defaultheader, + cachekey: `mdmsv2Seacrh${requestBody?.MdmsCriteria?.tenantId}${sheetName}${type}.${sheetName}${requestBody?.MdmsCriteria?.schemaCode}` + } + const response = await httpRequest(url, requestBody, undefined, undefined, undefined, header); + if (!response?.mdms?.[0]?.data) { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during customSheet config search"); + } + return response?.mdms?.[0]?.data; +} + +function getConvertedSheetData(allRows: any) { + const headersSet = new Set(); + allRows.forEach((row: any) => { + Object.keys(row).forEach(header => headersSet.add(header)); + }); + const headers: any = Array.from(headersSet); + + // Map rows to include all headers, filling missing values with "" + const sheetData = allRows.map((row: any) => + headers.map((header: any) => row[header] || "") + ); + + sheetData.unshift(headers); + return sheetData; +} +async function makeCustomSheetData(request: any, type: any, sheetName: any, workbook: any, localizationMap: any) { + const data = await getCustomSheetData(request, type, sheetName); + const sheetNameAfterTranslation = getLocalizedName(sheetName, localizationMap); + const customSheet = workbook.addWorksheet(sheetNameAfterTranslation); + const allRows: any = [] + for (const rows of data?.data) { + const rowData: any = {} + for (const row of rows) { + rowData[getLocalizedName(row?.column, localizationMap)] = getLocalizedName(row?.value, localizationMap); + } + allRows.push(rowData); + } + const sheetData = getConvertedSheetData(allRows); + addDataToSheet(request, customSheet, sheetData, undefined, undefined); + customSheet.protect('passwordhere', { + selectLockedCells: true, + selectUnlockedCells: true + }); +} + +async function generateUserSheetForMicroPlan( + request: any, + rolesForMicroplan: string[], + userData?: any, + localizationMap?: any, + fileUrl?: any +) { + const { tenantId, type } = request?.query; + const schema = await callMdmsTypeSchema(request, tenantId, false, "user", "microplan"); + setDropdownFromSchema(request, schema, localizationMap); + const headers = schema?.columns; + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + + logger.info("Generated an empty user template"); + + const workbook = getNewExcelWorkbook(); + const userSheetData = await createExcelSheet(userData, localizedHeaders); // Create data only once + + // Create and add ReadMe sheet + const headingInSheet = headingMapping?.[type]; + const localizedHeading = getLocalizedName(headingInSheet, localizationMap); + await createReadMeSheet(request, workbook, localizedHeading, localizationMap); + + + await makeCustomSheetData(request, request?.query?.type, "USER_MICROPLAN_SHEET_ROLES", workbook, localizationMap); + + // Loop through the rolesForMicroplan array to create sheets for each role + for (const role of rolesForMicroplan) { + // Create a sheet for each role, using the role name as the sheet name + const userSheet: any = workbook.addWorksheet(role); + addDataToSheet(request, userSheet, userSheetData, undefined, undefined, true, false, localizationMap, fileUrl, schema); + await handledropdownthings(userSheet, request.body?.dropdowns); + await handleHiddenColumns(userSheet, request.body?.hiddenColumns); + } + + // Create and upload the workbook file + const fileDetails = await createAndUploadFile(workbook, request); + request.body.fileDetails = fileDetails; +} + + + + +async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, fileUrl?: any) { + const userData: any[] = []; + const tenantId = request?.query?.tenantId; + const isSourceMicroplan = await isMicroplanRequest(request); + if (isSourceMicroplan) { + const rolesForMicroplan = await getRolesForMicroplan(tenantId, localizationMap); + await generateUserSheetForMicroPlan(request, rolesForMicroplan, userData, localizationMap, fileUrl); + } + else { + await generateUserSheet(request, localizationMap, filteredBoundary, userData, fileUrl); + } +} + +async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, fileUrl?: string) { const { type, tenantId } = request.query if (type == "facilityWithBoundary") { - await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap, filteredBoundary); + await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap, filteredBoundary, fileUrl); } if (type == "userWithBoundary") { - await generateUserAndBoundarySheet(request, localizationMap, filteredBoundary); + await generateUserAndBoundarySheet(request, localizationMap, filteredBoundary, fileUrl); } } async function processGenerateForNew(request: any, generatedResource: any, newEntryResponse: any, enableCaching = false, filteredBoundary?: any) { request.body.generatedResource = newEntryResponse; + logger.info("Generate flow :: processing new request"); await fullProcessFlowForNewEntry(newEntryResponse, generatedResource, request, enableCaching, filteredBoundary); return request.body.generatedResource; } @@ -794,7 +1069,8 @@ async function processGenerateForNew(request: any, generatedResource: any, newEn async function handleGenerateError(newEntryResponse: any, generatedResource: any, error: any) { newEntryResponse.map((item: any) => { item.status = generatedResourceStatuses.failed, item.additionalDetails = { - ...item.additionalDetails, error: { + ...item.additionalDetails, + error: { status: error.status, code: error.code, description: error.description, @@ -852,6 +1128,7 @@ async function enrichResourceDetails(request: any) { else { request.body.ResourceDetails.status = resourceDataStatuses.started } + request.body.ResourceDetails.auditDetails = { createdBy: request?.body?.RequestInfo?.userInfo?.uuid, createdTime: Date.now(), @@ -941,9 +1218,7 @@ function modifyBoundaryData(boundaryData: any[], localizationMap?: any) { return [withBoundaryCode, withoutBoundaryCode]; } - -async function getDataFromSheet(request: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, optionalSheetName?: any, localizationMap?: { [key: string]: string }) { - const type = request?.body?.ResourceDetails?.type; +async function getDataFromSheetFromNormalCampaign(type: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, optionalSheetName?: any, localizationMap?: { [key: string]: string }) { const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); if (!fileResponse?.fileStoreIds?.[0]?.url) { throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); @@ -952,17 +1227,35 @@ async function getDataFromSheet(request: any, fileStoreId: any, tenantId: any, c return await getTargetSheetData(fileResponse?.fileStoreIds?.[0]?.url, true, true, localizationMap); } return await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, createAndSearchConfig?.parseArrayConfig?.sheetName || optionalSheetName, true, createAndSearchConfig, localizationMap) + +} + + +async function getDataFromSheet(request: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, optionalSheetName?: any, localizationMap?: { [key: string]: string }) { + const isSourceMicroplan = request?.body?.ResourceDetails?.additionalDetails?.source == "microplan"; + const type = request?.body?.ResourceDetails?.type; + if (isSourceMicroplan) { + if (type == 'user') { + return await getUserDataFromMicroplanSheet(request, fileStoreId, tenantId, createAndSearchConfig, localizationMap); + } + else { + return await getDataFromSheetFromNormalCampaign(type, fileStoreId, tenantId, createAndSearchConfig, optionalSheetName, localizationMap); + } + } + else { + return await getDataFromSheetFromNormalCampaign(type, fileStoreId, tenantId, createAndSearchConfig, optionalSheetName, localizationMap); + } } async function getBoundaryRelationshipData(request: any, params: any) { - logger.info("Boundary relationship search initiated") + logger.info("Boundary relationship search initiated"); const url = `${config.host.boundaryHost}${config.paths.boundaryRelationship}`; const header = { ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + // cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, } const boundaryRelationshipResponse = await httpRequest(url, request.body, params, undefined, undefined, header); - logger.info("Boundary relationship search response received") + logger.info("Boundary relationship search response received"); return boundaryRelationshipResponse?.TenantBoundary?.[0]?.boundary; } @@ -977,13 +1270,15 @@ async function getDataSheetReady(boundaryData: any, request: any, localizationMa const hierarchy = await getHierarchy(request, request?.query?.tenantId, request?.query?.hierarchyType); const startIndex = boundaryType ? hierarchy.indexOf(boundaryType) : -1; const reducedHierarchy = startIndex !== -1 ? hierarchy.slice(startIndex) : hierarchy; - const modifiedReducedHierarchy = reducedHierarchy.map(ele => `${request?.query?.hierarchyType}_${ele}`.toUpperCase()) + const modifiedReducedHierarchy = getLocalizedHeaders(reducedHierarchy.map(ele => `${request?.query?.hierarchyType}_${ele}`.toUpperCase()), localizationMap); // get Campaign Details from Campaign Search Api var configurableColumnHeadersBasedOnCampaignType: any[] = [] if (type == "boundary") { configurableColumnHeadersBasedOnCampaignType = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); } - + if (type == "boundaryManagement" || type == "boundaryGeometryManagement") { + configurableColumnHeadersBasedOnCampaignType = await getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement(request, localizationMap); + } const headers = (type !== "facilityWithBoundary" && type !== "userWithBoundary") ? [ ...modifiedReducedHierarchy, @@ -994,9 +1289,11 @@ async function getDataSheetReady(boundaryData: any, request: any, localizationMa getBoundaryColumnName() ]; const localizedHeaders = getLocalizedHeaders(headers, localizationMap); - const data = boundaryList.map(boundary => { + var boundaryCodeList: any[] = []; + var data = boundaryList.map(boundary => { const boundaryParts = boundary.split(','); const boundaryCode = boundaryParts[boundaryParts.length - 1]; + boundaryCodeList.push(boundaryCode); const rowData = boundaryParts.concat(Array(Math.max(0, reducedHierarchy.length - boundaryParts.length)).fill('')); // localize the boundary codes const mappedRowData = rowData.map((cell: any, index: number) => @@ -1006,6 +1303,19 @@ async function getDataSheetReady(boundaryData: any, request: any, localizationMa mappedRowData[boundaryCodeIndex] = boundaryCode; return mappedRowData; }); + if(type == "boundaryManagement"){ + logger.info("Processing data for boundaryManagement type") + const latLongBoundaryMap = await getLatLongMapForBoundaryCodes(request, boundaryCodeList); + for (let d of data) { + const boundaryCode = d[d.length - 1]; // Assume last element is the boundary code + + if (latLongBoundaryMap[boundaryCode]) { + const [latitude = null, longitude = null] = latLongBoundaryMap[boundaryCode]; // Destructure lat/long + d.push(latitude); // Append latitude + d.push(longitude); // Append longitude + } + } + } const sheetRowCount = data.length; if (type != "facilityWithBoundary") { request.body.generatedResourceCount = sheetRowCount; @@ -1046,10 +1356,10 @@ function modifyDataBasedOnDifferentTab(boundaryData: any, differentTabsBasedOnLe } -async function getLocalizedMessagesHandler(request: any, tenantId: any, module = config.localisation.localizationModule) { +async function getLocalizedMessagesHandler(request: any, tenantId: any, module = config.localisation.localizationModule, overrideCache = false) { const localisationcontroller = Localisation.getInstance(); const locale = getLocaleFromRequest(request); - const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId); + const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId,overrideCache); return localizationResponse; } @@ -1062,16 +1372,22 @@ async function getLocalizedMessagesHandlerViaRequestInfo(RequestInfo: any, tenan -async function translateSchema(schema: any, localizationMap?: { [key: string]: string }) { +async function translateSchema( + schema: any, + localizationMap?: { [key: string]: string }) { const translatedSchema = { ...schema, properties: Object.entries(schema?.properties || {}).reduce((acc, [key, value]) => { const localizedMessage = getLocalizedName(key, localizationMap); acc[localizedMessage] = value; return acc; - }, {} as { [key: string]: any }), // Initialize with the correct type - required: (schema?.required || []).map((key: string) => getLocalizedName(key, localizationMap)), - unique: (schema?.unique || []).map((key: string) => getLocalizedName(key, localizationMap)) + }, {} as { [key: string]: any }), + + required: (schema?.required || []) + .map((key: string) => getLocalizedName(key, localizationMap)), + + unique: (schema?.unique || []) + .map((key: string) => getLocalizedName(key, localizationMap)) }; return translatedSchema; @@ -1095,7 +1411,7 @@ function getDifferentDistrictTabs(boundaryData: any, differentTabsBasedOnLevel: const rowData = Object.values(data); const districtValue = data[differentTabsBasedOnLevel]; const districtIndex = districtValue !== '' ? rowData.indexOf(districtValue) : -1; - // replaced '_' with '#' to avoid errors caused by underscores in boundary codes. + if (districtIndex != -1) { const districtLevelRow = rowData.slice(0, districtIndex + 1); const districtKey = districtLevelRow.join('#'); @@ -1136,7 +1452,7 @@ async function getMdmsDataBasedOnCampaignType(request: any, localizationMap?: an let campaignType = campaignObject.projectType; const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); campaignType = (isSourceMicroplan) ? `${config?.prefixForMicroplanCampaigns}-${campaignType}` : campaignType; - const mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) + const mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, false, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) return mdmsResponse; } @@ -1233,7 +1549,7 @@ export { getMdmsDataBasedOnCampaignType, shutdownGracefully, appendProjectTypeToCapacity, - getLocalizedMessagesHandlerViaRequestInfo + getLocalizedMessagesHandlerViaRequestInfo, + createFacilityAndBoundaryFile, + hideUniqueIdentifierColumn }; - - diff --git a/health-services/project-factory/src/server/utils/logger/index.ts b/health-services/project-factory/src/server/utils/logger/index.ts index f2cad55890b..2e43c0011bf 100644 --- a/health-services/project-factory/src/server/utils/logger/index.ts +++ b/health-services/project-factory/src/server/utils/logger/index.ts @@ -25,8 +25,17 @@ export { logger }; const DEFAULT_LOG_MESSAGE_COUNT = config.app.debugLogCharLimit; -export const getFormattedStringForDebug = (obj: any) => { - const convertedMessage=JSON.stringify(obj); - return convertedMessage?.slice(0, DEFAULT_LOG_MESSAGE_COUNT) + - (convertedMessage?.length > DEFAULT_LOG_MESSAGE_COUNT ? "\n ---more" : ""); -} +export const getFormattedStringForDebug = (obj: any): string => { + try { + const convertedMessage = JSON.stringify(obj); + return convertedMessage.slice(0, DEFAULT_LOG_MESSAGE_COUNT) + + (convertedMessage.length > DEFAULT_LOG_MESSAGE_COUNT ? "\n ---more" : ""); + } catch (error : any ) { + if (error instanceof RangeError && error.message.includes("Invalid string length")) { + logger.error("The object is too big to convert into a string."); + } else { + logger.error(`An unexpected error occurred while formatting the object into a string : ${error?.message}`); + } + return "Error: Unable to format object for debug."; + } +}; diff --git a/health-services/project-factory/src/server/utils/microplanIntergration.ts b/health-services/project-factory/src/server/utils/microplanIntergration.ts new file mode 100644 index 00000000000..15f0d5713b8 --- /dev/null +++ b/health-services/project-factory/src/server/utils/microplanIntergration.ts @@ -0,0 +1,985 @@ +import { + callMdmsTypeSchema, + createAndUploadFile, + searchMDMS, +} from "../api/genericApis"; +import { getFormattedStringForDebug, logger } from "./logger"; + +import { + searchProjectTypeCampaignService, + updateProjectTypeCampaignService, +} from "../service/campaignManageService"; +import { + searchPlan, + searchPlanCensus, + searchPlanFacility, +} from "../api/microplanApis"; +import { + createAndPollForCompletion, + getTheGeneratedResource, +} from "./pollUtils"; +import { getExcelWorkbookFromFileURL } from "./excelUtils"; +import { + fetchFileFromFilestore, + searchBoundaryRelationshipData, + searchMDMSDataViaV1Api, +} from "../api/coreApis"; +import { getLocalizedName } from "./campaignUtils"; +import config from "../config"; +import { replicateRequest, throwError } from "./genericUtils"; +import { MDMSModels } from "../models"; +/** + * Adds data rows to the provided worksheet. + * @param worksheet The worksheet to which the data should be added. + * @param data Array of data rows to add. + */ +export async function addDataToWorksheet(worksheet: any, data: string[][]) { + data.forEach((row) => { + worksheet.addRow(row); + }); + + // Optionally, you can apply styles or adjust column widths + worksheet.columns.forEach((column: any) => { + column.width = 20; // Adjust column width to fit content + }); +} + +/** + * Updates existing rows in a worksheet with the given data, starting from row 2. + * @param worksheet The worksheet to update. + * @param data Array of data rows to insert. + */ +function updateWorksheetRows(worksheet: any, data: string[][]) { + data.forEach((rowData, index) => { + const rowNumber = 2 + index; // Start updating from row 2 + const row = worksheet.getRow(rowNumber); + + // Set values for each column in the row + rowData.forEach((cellValue, colIndex) => { + row.getCell(colIndex + 1).value = cellValue; // Column index starts at 1 + }); + + row.commit(); // Commit changes to the row + }); +} + +const getPlanFacilityMapByFacilityId = (planFacilityArray: any = []) => { + logger.info( + `filtered the plan facility response to have only facility which has only service boundarires` + ); + return planFacilityArray + ?.filter( + (planFacilityObj: any) => planFacilityObj?.serviceBoundaries?.length > 0 + ) + ?.reduce((acc: any, curr: any) => { + acc[curr?.facilityId] = curr; + return acc; + }, {}); +}; +const getRolesAndCount = (resources = [], userRoleMapping: any) => { + const USER_ROLE_MAP: any = {}; + + // Iterate through the userRoleMapping to determine rules for roles + userRoleMapping?.user?.forEach((mapping: any) => { + const { to, from, filter } = mapping; + + resources?.forEach((resource: any) => { + // Apply filter logic ensuring all criteria in `from` must match + const match = from.every((criteria: string) => + filter === "includes" + ? resource?.resourceType?.includes(criteria) + : resource?.resourceType === criteria + ); + + if (match) { + // Log the resource information + logger.info( + `filtered ${filter.toUpperCase()}: ${resource?.resourceType} :: ${ + resource?.estimatedNumber + }` + ); + + // Map roles based on the "to" field + USER_ROLE_MAP[to] = resource?.estimatedNumber; + } + }); + }); + + logger.info("Completed user role & boundary map"); + logger.info(`Map USER_ROLE_MAP ${getFormattedStringForDebug(USER_ROLE_MAP)}`); + + return { USER_ROLE_MAP }; +}; + +const getUserRoleMapWithBoundaryCode = ( + planFacilityArray: any = [], + userRoleMapping: any +) => { + return planFacilityArray?.reduce((acc: any, curr: any) => { + acc[curr?.locality] = { + // ...curr, + ...getRolesAndCount( + curr?.resources?.filter( + (resource: any) => resource?.estimatedNumber > 0 + ), + userRoleMapping + ), + }; + return acc; + }, {}); +}; + +function consolidateUserRoles( + userBoundaryMap: any, + boundaryiwthchildrednMap: any +) { + const result: any = {}; + + // Iterate through all parent boundaries + for (const parentBoundary in boundaryiwthchildrednMap) { + const children = boundaryiwthchildrednMap[parentBoundary]; + const consolidatedRoles: any = {}; + + // Process each child boundary + children.forEach((child: any) => { + const childCode = child.code; + const userRoles = userBoundaryMap[childCode]?.USER_ROLE_MAP || {}; + + // Aggregate roles for the parent boundary + for (const role in userRoles) { + if (!consolidatedRoles[role]) { + consolidatedRoles[role] = 0; + } + consolidatedRoles[role] += userRoles[role]; + } + }); + + // Attach consolidated roles to the parent boundary + result[parentBoundary] = { + parentBoundary, + children, + consolidatedRoles, + }; + } + + return result; +} + +// // Example Usage +// const consolidatedData = consolidateUserRoles(userBoundaryMap, boundaryiwthchildrednMap); +// console.log(JSON.stringify(consolidatedData, null, 2)); + +const getPlanCensusMapByBoundaryCode = (censusArray: any = []) => { + return censusArray?.reduce((acc: any, curr: any) => { + acc[curr?.boundaryCode] = curr; + return acc; + }, {}); +}; + +export const fetchFacilityData = async (request: any, localizationMap: any) => { + const { tenantId, planConfigurationId, campaignId } = + request.body.MicroplanDetails; + logger.info( + `doing the facility data fetch for planConfigurationId: ${planConfigurationId} and campaignId: ${campaignId} ` + ); + const facilityAdminSchema = await callMdmsTypeSchema( + request, + tenantId, + true, + "facility" + ); + const localizedHeadersMap = getLocalizedHeadersMapForFacility( + facilityAdminSchema.descriptionToFieldMap, + localizationMap + ); + const planFacilityResponse = await searchPlanFacility( + planConfigurationId, + tenantId + ); + logger.info(`got the facility mapping from the plan facility api`); + + const facilityBoundaryMap = + getPlanFacilityMapByFacilityId(planFacilityResponse); + logger.debug( + `created facilityBoundaryMap :${getFormattedStringForDebug( + facilityBoundaryMap + )}` + ); + + const generatedFacilityTemplateFileStoreId = await getTheGeneratedResource( + campaignId, + tenantId, + "facilityWithBoundary", + request.body.CampaignDetails?.hierarchyType + ); + logger.debug( + `downloadresponse fetchFacilityData ${getFormattedStringForDebug( + generatedFacilityTemplateFileStoreId + )}` + ); + const fileUrl = await fetchFileFromFilestore( + generatedFacilityTemplateFileStoreId, + tenantId + ); + logger.debug( + `downloadresponse fileUrl ${getFormattedStringForDebug(fileUrl)}` + ); + const workbook = await getExcelWorkbookFromFileURL( + fileUrl, + getLocalizedName(config?.facility?.facilityTab, localizationMap) + ); + logger.info(`workbook created for facility`); + + const updatedWorksheet = await findAndChangeFacilityData( + workbook.getWorksheet( + getLocalizedName(config?.facility?.facilityTab, localizationMap) + ), + facilityBoundaryMap, + localizedHeadersMap + ); + logger.info( + `workbook updated for facility with the data received from microplan` + ); + + const responseData = + updatedWorksheet && (await createAndUploadFile(workbook, request)); + logger.info( + "facility File updated successfully:" + JSON.stringify(responseData) + ); + if (responseData?.[0]?.fileStoreId) { + logger.info( + "facility File updated successfully:" + + JSON.stringify( + responseData?.[0]?.fileStoreId + " for campaignid : " + campaignId + ) + ); + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } + + const polledResponseOfDataCreate = await validateSheet( + request, + tenantId, + "facility", + responseData?.[0]?.fileStoreId, + campaignId, + request.body.CampaignDetails.hierarchyType + ); + if ( + Array.isArray(polledResponseOfDataCreate) && + polledResponseOfDataCreate.length > 0 + ) { + await updateCampaignDetailsAfterSearch( + request, + polledResponseOfDataCreate?.[0], + "facility" + ); + logger.info( + `updated the resources of facility resource id ${polledResponseOfDataCreate?.[0]?.id}` + ); + } + logger.info( + `updated the resources of facility for campaignid : ${campaignId} and planid: ${planConfigurationId} ` + ); +}; + +function getLocalizedHeadersMapForFacility( + descriptionToFieldMap: Record, + localizationMap: any +) { + for (const [key, value] of Object.entries(descriptionToFieldMap)) { + descriptionToFieldMap[key] = getLocalizedName(value, localizationMap); + } + return descriptionToFieldMap; +} + +export const fetchTargetData = async (request: any, localizationMap: any) => { + const { tenantId, planConfigurationId, campaignId } = + request.body.MicroplanDetails; + logger.info( + `doing the target data fetch for planConfigurationId: ${planConfigurationId} and campaignId: ${campaignId} ` + ); + + const { projectType } = request.body.CampaignDetails; + const campaignType = "Target-" + projectType; + const userRoleMapping = await fetchUserRoleMappingFromMDMS(tenantId); + logger.info("received mdms data for target column mapping"); + logger.debug( + `target column mapping ${getFormattedStringForDebug(userRoleMapping)}` + ); + const planCensusResponse = await searchPlanCensus( + planConfigurationId, + tenantId, + getBoundariesFromCampaign(request.body.CampaignDetails)?.length + ); + logger.info(`got the target mapping from the census api`); + + const targetBoundaryMap = getPlanCensusMapByBoundaryCode(planCensusResponse); + logger.debug( + `created targetBoundaryMap :${getFormattedStringForDebug( + targetBoundaryMap + )}` + ); + + const generatedTargetTemplateFileStoreId = await getTheGeneratedResource( + campaignId, + tenantId, + "boundary", + request.body.CampaignDetails?.hierarchyType + ); + logger.debug( + `downloadresponse target ${getFormattedStringForDebug( + generatedTargetTemplateFileStoreId + )}` + ); + const fileUrl = await fetchFileFromFilestore( + generatedTargetTemplateFileStoreId, + tenantId + ); + logger.debug( + `downloadresponse target ${getFormattedStringForDebug(fileUrl)}` + ); + + const workbook = await getExcelWorkbookFromFileURL(fileUrl); + logger.info(`workbook created for target`); + + await workbook.worksheets.forEach(async (worksheet) => { + logger.info(`Processing worksheet: ${worksheet.name}`); + logger.info(`skipping processing worksheet: ${getLocalizedName(config?.boundary?.boundaryTab, localizationMap)} and ${getLocalizedName(config?.values?.readMeTab, localizationMap)} `); + + if ( + worksheet.name !== + getLocalizedName(config?.boundary?.boundaryTab, localizationMap) && + worksheet.name !== + getLocalizedName(config?.values?.readMeTab, localizationMap) + ) { + // harcoded to be changed + // Iterate over rows (skip the header row) + await findAndChangeTargetData( + worksheet, + targetBoundaryMap, + userRoleMapping[campaignType], + localizationMap + ); + } + }); + logger.info( + `workbook updated for target with the data received from microplan` + ); + + const responseData = await createAndUploadFile(workbook, request); + + logger.info( + "Target File updated successfully:" + JSON.stringify(responseData) + ); + if (responseData?.[0]?.fileStoreId) { + logger.info( + "Target File updated successfully:" + + JSON.stringify( + responseData?.[0]?.fileStoreId + " for campaignid : " + campaignId + ) + ); + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } + const polledResponseOfDataCreate = await validateSheet( + request, + tenantId, + "boundaryWithTarget", + responseData?.[0]?.fileStoreId, + campaignId, + request.body.CampaignDetails.hierarchyType + ); + + if ( + Array.isArray(polledResponseOfDataCreate) && + polledResponseOfDataCreate.length > 0 + ) { + await updateCampaignDetailsAfterSearch( + request, + polledResponseOfDataCreate?.[0], + "boundaryWithTarget" + ); + logger.info( + `updated the resources of facility resource id ${polledResponseOfDataCreate?.[0]?.id}` + ); + } + logger.info( + `updated the resources of target for campaignid : ${campaignId} and planid: ${planConfigurationId} ` + ); +}; + +function findAndChangeUserData(worksheet: any, mappingData: any) { + logger.info( + `Received for facility mapping, enitity count : ${ + Object.keys(mappingData)?.length + }` + ); + logger.debug(`${getFormattedStringForDebug(mappingData)}, "mappingData user`); + // column no is // harcoded to be changed + const mappedData: any = {}; + + const dataRows: any = []; + Object.keys(mappingData).map((key) => { + const roles = Object.keys(mappingData[key].consolidatedRoles); + roles.map((role) => { + for (let i = 0; i < mappingData[key].consolidatedRoles?.[role]; i++) { + dataRows.push(["", "", role, "Permanent", key, "Active"]); + } + }); + }); + logger.debug( + `${getFormattedStringForDebug(dataRows)},"dataRows to be pushed` + ); + updateWorksheetRows(worksheet, dataRows); + + logger.info( + `Updated the boundary & active/inactive status information in facility received from the microplan` + ); + logger.info( + `mapping completed for facility enitity count : ${ + Object.keys(mappedData)?.length + }` + ); + logger.info( + `mapping not found for facility entity count : ${ + Object.keys(mappingData)?.length - Object.keys(mappedData)?.length + }` + ); + return worksheet; +} + +function findAndChangeFacilityData( + worksheet: any, + mappingData: Record< + string, + { + additionalDetails: any; + serviceBoundaries: string[]; + } + >, + headersMap: Record +) { + let facilityCodeIndex: number = 1; + let boundaryCodeIndex: number = 6; + let facilityUsageIndex: number = 7; + let headerValues: any = []; + + const mappedData: Record = {}; + const missingFacilities: string[] = []; + + // Iterate through each row in the worksheet + worksheet.eachRow((row: any, rowIndex: number) => { + if (rowIndex === 1) { + headerValues = row.values; + facilityCodeIndex = headerValues.indexOf("Facility Code"); + boundaryCodeIndex = headerValues.indexOf(headersMap["Boundary Code"]); + facilityUsageIndex = headerValues.indexOf(headersMap["Facility usage"]); + return; + } + + const facilityCode = row.getCell(facilityCodeIndex).value; + if (facilityCode && mappingData[facilityCode]) { + const facilityDetails = mappingData[facilityCode]; + row.getCell(boundaryCodeIndex).value = + facilityDetails.serviceBoundaries.join(",") || ""; + row.getCell(facilityUsageIndex).value = "Active"; + mappedData[facilityCode] = true; + } else { + row.getCell(boundaryCodeIndex).value = ""; + row.getCell(facilityUsageIndex).value = "Inactive"; + } + }); + + // Handle missing facilities + for (const [facilityCode, facilityDetails] of Object.entries(mappingData)) { + if (!mappedData[facilityCode]) { + missingFacilities.push(facilityCode); + + // Find the first empty row in the sheet + let emptyRowIndex = worksheet.rowCount + 1; // Default to the next available row + for (let i = 1; i <= worksheet.rowCount; i++) { + const row = worksheet.getRow(i); + if (!row.getCell(1).value) { // Assuming column 1 is used to determine emptiness + emptyRowIndex = i; + break; + } + } + + const newRow = worksheet.getRow(emptyRowIndex); + + // Assign values to the identified empty row + newRow.getCell(facilityCodeIndex).value = facilityCode; + newRow.getCell(headerValues.indexOf(headersMap["Facility Name"])).value = + facilityDetails?.additionalDetails?.facilityName; + newRow.getCell(headerValues.indexOf(headersMap["Facility type"])).value = + facilityDetails?.additionalDetails?.facilityType; + newRow.getCell( + headerValues.indexOf(headersMap["Facility status"]) + ).value = facilityDetails?.additionalDetails?.facilityStatus; + newRow.getCell(headerValues.indexOf(headersMap["Capacity"])).value = + facilityDetails?.additionalDetails?.capacity; + newRow.getCell(boundaryCodeIndex).value = + facilityDetails.serviceBoundaries.join(",") || ""; + newRow.getCell(facilityUsageIndex).value = "Active"; + + newRow.commit(); // Save the changes to the row + } + } + + logger.info( + `Updated the boundary & active/inactive status information in facility received from the microplan` + ); + logger.info( + `mapping completed for facility enitity count : ${ + Object.keys(mappedData)?.length + }` + ); + + return worksheet; +} + +function getHeaderIndex( + headers: any, + headerName: string, + localizationMap: any +) { + return headers.indexOf( + getLocalizedName(headerName, localizationMap) + ); +} + +function findAndChangeTargetData( + worksheet: any, + mappingData: any, + headers: any, + localizationMap: any +) { + logger.info( + `Received for Target mapping, enitity count : ${ + Object.keys(mappingData)?.length + }` + ); + + if (headers == null || headers.length == 0) { + throwError("Error", 500, "Mapping not found in MDMS for Campaign"); + } + logger.info( + `Received for Target mapping, headers count : ${ + headers?.length + }` + ); + logger.debug( + `headers: ${getFormattedStringForDebug(headers)}` + ); + let headersInSheet = worksheet.getRow(1).values; + const mappedData: any = {}; + // Iterate through rows in Sheet1 (starting from row 2 to skip the header) + worksheet.eachRow((row: any, rowIndex: number) => { + if (rowIndex === 1) return; // Skip the header row + const column1Value = row.getCell( + getHeaderIndex( + headersInSheet, + config?.boundary?.boundaryCode, + localizationMap + ) + ).value; // Get the value from column 1 + logger.debug( + `column1Value: ${getFormattedStringForDebug(column1Value)}` + ); + if (mappingData?.[column1Value] && headers != null && headers.length > 0) { + // Update columns 5 and 6 if column 1 value matches + headers.forEach((header: any) => { + header.from.forEach((fromValue: any) => { + row.getCell( + getHeaderIndex(headersInSheet, header?.to, localizationMap) + ).value = + mappingData?.[column1Value]?.additionalDetails?.[ + fromValue + ]; + logger.debug( + `headers to: ${getFormattedStringForDebug(getLocalizedName(header?.to, localizationMap))}` + ); + }); + }) + mappedData[column1Value] = rowIndex; + } else { + logger.info(`not doing anything if taregt cel not found`); + // Default values for other rows + // row.getCell(6).value = ""; + // row.getCell(7).value = "Inactive"; + } + }); + logger.info( + `Updated the boundary & active/inactive status information in Target received from the microplan` + ); + logger.info( + `mapping completed for Target enitity count : ${ + Object.keys(mappedData)?.length + }` + ); + logger.info( + `mapping not found for Target entity count : ${ + Object.keys(mappingData)?.length - Object.keys(mappedData)?.length + }` + ); + return worksheet; +} + +const getBoundariesFromCampaign = (CampaignDetails: any = {}) => { + logger.info("fetching all boundaries in that CampaignDetails"); + const boundaries = CampaignDetails?.boundaries?.map((obj: any) => obj?.code); + logger.debug( + `boundaries in that CampaignDetails are :${getFormattedStringForDebug( + boundaries + )}` + ); + return boundaries; +}; + +export const fetchUserData = async (request: any, localizationMap: any) => { + const { tenantId, planConfigurationId, campaignId } = + request.body.MicroplanDetails; + logger.info( + `doing the user data fetch for planConfigurationId: ${planConfigurationId} and campaignId: ${campaignId} ` + ); + const userRoleMapping = await fetchUserRoleMappingFromMDMS(tenantId); + logger.info(`got the user mapping from the plan api`); + const hierarchySchemaDataForConsole = await searchMDMS( + ["console"], + "HCM-ADMIN-CONSOLE.HierarchySchema", + request.body.RequestInfo + ); + const planResponse = await searchPlan( + planConfigurationId, + tenantId, + getBoundariesFromCampaign(request.body.CampaignDetails)?.length + ); + const boundariesOfCampaign = await getBoundaryInformation( + request.body.CampaignDetails, + request.body.CampaignDetails?.hierarchyType, + tenantId + ); + const filteredBoundariesAtWhichUserGetsCreated = + getFilteredBoundariesAtWhichUserGetsCreated( + boundariesOfCampaign, + hierarchySchemaDataForConsole?.mdms + ); + logger.debug( + `boundariesOfCampaign : ${getFormattedStringForDebug(boundariesOfCampaign)}` + ); + + const filteredBoundaryCodeMapWithChildrens = + enrichBoundariesWithTheSelectedChildrens( + boundariesOfCampaign, + filteredBoundariesAtWhichUserGetsCreated + ); + logger.debug( + `filteredBoundaryCodeMapWithChildrens : ${getFormattedStringForDebug( + filteredBoundaryCodeMapWithChildrens + )}` + ); + + const boundaryWithRoleMap = getUserRoleMapWithBoundaryCode( + planResponse, + userRoleMapping + ); + logger.debug( + `created userBoundaryMap :${getFormattedStringForDebug( + boundaryWithRoleMap + )}` + ); + + const consolidatedUserRolesPerBoundary = consolidateUserRoles( + boundaryWithRoleMap, + filteredBoundaryCodeMapWithChildrens + ); + + logger.debug( + `created final consolidatedUserRolesPerBoundary :${getFormattedStringForDebug( + consolidatedUserRolesPerBoundary + )}` + ); + const generatedUserTemplateFileStoreId = await getTheGeneratedResource( + campaignId, + tenantId, + "userWithBoundary", + request.body.CampaignDetails?.hierarchyType + ); + logger.debug( + `downloadresponse userWithBoundary ${getFormattedStringForDebug( + generatedUserTemplateFileStoreId + )}` + ); + const fileUrl = await fetchFileFromFilestore( + generatedUserTemplateFileStoreId, + tenantId + ); + logger.debug( + `downloadresponse userWithBoundary ${getFormattedStringForDebug(fileUrl)}` + ); + + const workbook = await getExcelWorkbookFromFileURL( + fileUrl, + getLocalizedName(config?.user.userTab, localizationMap) + ); + logger.info(`workbook created for user`); + + const updatedWorksheet = await findAndChangeUserData( + workbook.getWorksheet( + getLocalizedName(config?.user.userTab, localizationMap) + ), + consolidatedUserRolesPerBoundary + ); + logger.info( + `workbook updated for user with the data received from microplan` + ); + const responseData = + updatedWorksheet && (await createAndUploadFile(workbook, request)); + logger.info("user File updated successfully:" + JSON.stringify(responseData)); + if (responseData?.[0]?.fileStoreId) { + logger.info( + "user File updated successfully:" + + JSON.stringify( + responseData?.[0]?.fileStoreId + " for campaignid : " + campaignId + ) + ); + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } + + await updateCampaignDetailsAfterSearch( + request, + { + fileStoreId: responseData?.[0]?.fileStoreId, + id: "not-validated", + }, + "user" + ); + + logger.info( + `updated the resources of user for campaignid : ${campaignId} and planid: ${planConfigurationId} ` + ); +}; + +export async function updateCampaignDetailsAfterSearch( + request: any, + resourceObject: any, + type: string +) { + const { tenantId, campaignId } = request.body.MicroplanDetails; + const campaignDetails = { + tenantId: tenantId, + ids: [campaignId], + }; + const searchedCampaignResponse = await searchProjectTypeCampaignService( + campaignDetails + ); + const searchedCamapignObject = + searchedCampaignResponse?.CampaignDetails?.[0] || null; + if (searchedCamapignObject != null) { + const newRequestBody = { + RequestInfo: request.body.RequestInfo, // Retain the original RequestInfo + CampaignDetails: searchedCamapignObject, // campaigndetails from search response + }; + const req: any = replicateRequest(request, newRequestBody); + // Validate input structure + if (resourceObject) { + let resourceFound = false; // Flag to track if resource is updated + + // Loop through resources to update or append as needed + searchedCamapignObject?.resources?.forEach((resource: any) => { + if (resource.type === type) { + resource.filestoreId = resourceObject?.fileStoreId; + resource.resourceId = resourceObject?.id; + logger.info( + `Updated resource of type ${type} with filestoreId: ${resourceObject.filestoreId}` + ); + resourceFound = true; + } + }); + + // If no resource of the given type was found, append a new one + if (!resourceFound) { + searchedCamapignObject?.resources.push({ + type: type, + filename: `filled-${type}-data-from-microplan.xlsx`, // Dynamically naming based on type + filestoreId: resourceObject?.fileStoreId, + resourceId: resourceObject?.id, + }); + logger.info(`Appended new resource of type ${type}`); + } + req.body.CampaignDetails = searchedCamapignObject; + } else { + console.error( + "Invalid structure in CampaignDetails or fileDetails. Ensure both are non-empty arrays." + ); + } + + // Call external service after updating the campaign details + await updateProjectTypeCampaignService(req); + } else { + throwError( + "CAMPAIGN", + 500, + "CAMPAIGN_SEARCH_ERROR", + "Error in Campaign Search" + ); + } +} + +export async function validateSheet( + request: any, + tenantId: any, + type: any, + fileStoreId: any, + campaignId: any, + hierarchyType: any +) { + let dataCreateBody = { + ResourceDetails: { + tenantId: tenantId, + type: type, + fileStoreId: fileStoreId, + action: "validate", + campaignId: campaignId, + hierarchyType: hierarchyType, + additionalDetails: {}, + }, + }; + + // Now merging defaultRequestInfo *with* dataCreateBody, so both are preserved + const newRequest: any = { + body: { ...request.body, ...dataCreateBody }, // Spread both objects to keep both their properties + }; + + try { + const resourceDetails:any = await createAndPollForCompletion(newRequest); + logger.info(`validation results :: ${resourceDetails?.[0]?.id} & status: ${resourceDetails?.[0]?.status}`) + logger.debug(`Final result:, ${getFormattedStringForDebug(resourceDetails)}`); + return resourceDetails; + } catch (error) { + logger.error( + `Error during resource creation and polling:for type ${type}`, + error + ); + logger.info(`setting resource event it fails for ${type}`); + return [{ ...dataCreateBody?.ResourceDetails, id: "not-validated" }]; + } +} +// sample oundary +//{code: "MICROPLAN_MO", name: "MICROPLAN_MO", parent:"", type: "COUNTRY", isRoot: true, includeAllChildren: false} +const getFilteredBoundariesAtWhichUserGetsCreated = ( + boundaries = [], + hierarchySchemaDataForConsole: any[] +) => { + // setting default value in case data is not present + let consolidateUserAtForConsole = "LOCALITY"; + if (hierarchySchemaDataForConsole?.length > 0) { + consolidateUserAtForConsole = + hierarchySchemaDataForConsole[0]?.data?.consolidateUsersAt; + logger.info( + "Taking value " + + consolidateUserAtForConsole + + " for user at console as it is present in mdms data" + ); + } else { + logger.info( + "Taking default value " + + consolidateUserAtForConsole + + " for user at console as it is not present in mdms data" + ); + } + //add config at which level grouping will happen. hardcoded to loclaity + const filteredBoundariesAtWhichUserGetsCreated = boundaries?.filter( + (boundary: any) => boundary?.type == consolidateUserAtForConsole + ); + logger.info( + `filteredBoundariesAtWhichUserGetsCreated count is ${filteredBoundariesAtWhichUserGetsCreated?.length}` + ); + logger.debug( + `filteredBoundariesAtWhichUserGetsCreated are ${getFormattedStringForDebug( + filteredBoundariesAtWhichUserGetsCreated + )}` + ); + return filteredBoundariesAtWhichUserGetsCreated; +}; + +const getBoundaryInformation = async ( + CampaignDetails: any, + boundaryHierarchy: string, + tenantId: string +) => { + const boundaries = CampaignDetails?.boundaries; + if (boundaries?.some((boundary: any) => boundary?.includeAllChildren)) { + const boundaryResponse = await searchBoundaryRelationshipData( + tenantId, + boundaryHierarchy, + true + ); + logger.info("got the boundary hierarchy response"); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + logger.info("got the boundary hierarchy response"); + } + + return boundaries; + } +}; + +const enrichBoundariesWithTheSelectedChildrens = ( + allSelectedBoundaries = [], + filteredBoundaries = [] +) => { + const enrichedMap: any = {}; + filteredBoundaries?.map((boundary: any) => { + enrichedMap[boundary?.code] = allSelectedBoundaries?.filter( + (bound: any) => bound.parent == boundary?.code + ); + }); + return enrichedMap; +}; +export async function fetchUserRoleMappingFromMDMS(tenantId: any) { + const MdmsCriteria: MDMSModels.MDMSv1RequestCriteria = { + MdmsCriteria: { + tenantId: tenantId, + moduleDetails: [ + { + moduleName: "HCM-ADMIN-CONSOLE", + masterDetails: [ + { + name: "microplanIntegration", + }, + ], + }, + ], + }, + }; + const data = await searchMDMSDataViaV1Api(MdmsCriteria); + const result: Record = {}; + + if ( + data?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.microplanIntegration && + Array.isArray(data.MdmsRes["HCM-ADMIN-CONSOLE"].microplanIntegration) + ) { + const integrations = + data.MdmsRes["HCM-ADMIN-CONSOLE"].microplanIntegration; + + integrations.forEach((integration: any) => { + const type = integration.type; + + if (!result[type]) { + result[type] = []; + } + + integration.mappings.forEach((mapping: any) => { + result[type].push({ + to: mapping.to, + from: mapping.from, + filter: mapping.filter, + }); + }); + }); + } + + return result; +} diff --git a/health-services/project-factory/src/server/utils/microplanUtils.ts b/health-services/project-factory/src/server/utils/microplanUtils.ts new file mode 100644 index 00000000000..1bae9d2a652 --- /dev/null +++ b/health-services/project-factory/src/server/utils/microplanUtils.ts @@ -0,0 +1,494 @@ +import { resourceDataStatuses } from "../config/constants"; +import { v4 as uuidv4 } from 'uuid'; +import config from "./../config"; +import { throwError } from "./genericUtils"; +import { httpRequest } from "./request"; +import { callMdmsData, getSheetData } from "./../api/genericApis"; +import { checkIfSourceIsMicroplan, getLocalizedName } from "./campaignUtils"; +import createAndSearch from "../config/createAndSearch"; +import { produceModifiedMessages } from "../kafka/Producer"; +import { searchMDMSDataViaV2Api } from "../api/coreApis"; +import { getCampaignSearchResponse } from "../api/campaignApis"; + + +export const filterData = (data: any) => { + return data.filter((item: any) => { + // Create a shallow copy of the object without `#status#` and `#errorDetails#` + const { '#status#': status, '#errorDetails#': errorDetails, ...rest } = item; + + // Check if only `!row#number!` remains after removing status and errorDetails + const remainingKeys = Object.keys(rest).filter(key => key !== '!row#number!'); + + // Include the item if any other properties exist besides `!row#number!` + return remainingKeys.length > 0; + }); +}; + + + + + +export async function getUserDataFromMicroplanSheet(request: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { + const fileResponse = await httpRequest(`${config.host.filestore}${config.paths.filestore}/url`, {}, { tenantId, fileStoreIds: fileStoreId }, "get"); + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); + } + const rolesForMicroplanWithCode = await getRolesForMicroplan(tenantId, localizationMap, true); + const rolesCodeMapping = rolesForMicroplanWithCode.reduce((acc: any, role: any) => { + acc[role.role] = role.code; + return acc; + }, {}); + const userMapping: any = {}; + for (const sheetName of Object.keys(rolesCodeMapping)) { + const dataOfSheet = filterData(await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, sheetName, true, undefined, localizationMap)); + for (const user of dataOfSheet) { + user.role = rolesCodeMapping?.[sheetName]; + user["!sheet#name!"] = sheetName; + const emailKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_EMAIL_MICROPLAN", localizationMap) + user[emailKey] = user[emailKey]?.text || user[emailKey]; + const phoneNumberKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER_MICROPLAN", localizationMap) + if (!userMapping[user[phoneNumberKey]]) { + userMapping[user[phoneNumberKey]] = [user] + } + else { + userMapping[user[phoneNumberKey]].push(user) + } + } + } + const allUserData = getAllUserData(request, userMapping, localizationMap); + return allUserData; +} + +export function getAllUserData(request: any, userMapping: any, localizationMap: any) { + const emailKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_EMAIL_MICROPLAN", localizationMap); + const nameKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_NAME_MICROPLAN", localizationMap); + const phoneNumberKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER_MICROPLAN", localizationMap); + validateInConsistency(request, userMapping, emailKey, nameKey); + validateNationalDuplicacy(request, userMapping, phoneNumberKey); + const dataToCreate: any = []; + for (const phoneNumber of Object.keys(userMapping)) { + const roles = userMapping[phoneNumber].map((user: any) => user.role).join(','); + const email = userMapping[phoneNumber]?.[0]?.[emailKey] || null; + const name = userMapping[phoneNumber]?.[0]?.[nameKey]; + const rowNumbers = userMapping[phoneNumber].map((user: any) => user["!row#number!"]); + const sheetNames = userMapping[phoneNumber].map((user: any) => user["!sheet#name!"]); + const tenantId = request?.body?.ResourceDetails?.tenantId; + const rowXSheet = rowNumbers.map((row: any, index: number) => ({ + row: row, + sheetName: sheetNames[index] + })); + dataToCreate.push({ ["!row#number!"]: rowXSheet, tenantId: tenantId, employeeType: "TEMPORARY", user: { emailId: email, name: name, mobileNumber: phoneNumber, roles: roles } }); + } + request.body.dataToCreate = dataToCreate; + return convertDataSheetWise(userMapping); +} + +function validateInConsistency(request: any, userMapping: any, emailKey: any, nameKey: any) { + const overallInconsistencies: string[] = []; // Collect all inconsistencies here + + enrichInconsistencies(overallInconsistencies, userMapping, nameKey, emailKey); + if (overallInconsistencies.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid + } + + request.body.sheetErrorDetails = Array.isArray(request.body.sheetErrorDetails) ? [...request.body.sheetErrorDetails, ...overallInconsistencies] : overallInconsistencies; +} + +function validateNationalDuplicacy(request: any, userMapping: any, phoneNumberKey: any) { + const duplicates: any[] = []; + + for (const phoneNumber in userMapping) { + const roleMap: any = {}; + const users = userMapping[phoneNumber]; + + for (const user of users) { + if (user.role?.startsWith("Root ")) { + // Trim the role + const trimmedRole = user.role.replace("Root ", "").trim().toLowerCase(); + const trimmedRoleWithCapital = trimmedRole.charAt(0).toUpperCase() + trimmedRole.slice(1); + + // Check for duplicates in the roleMap + if (roleMap[trimmedRole] && roleMap[trimmedRole]["!sheet#name!"] != user["!sheet#name!"]) { + const errorMessage: any = `An user with ${trimmedRoleWithCapital} role can’t be assigned to ${user.role} role`; + duplicates.push({ rowNumber: user["!row#number!"], sheetName: user["!sheet#name!"], status: "INVALID", errorDetails: errorMessage }); + } else { + roleMap[trimmedRole] = user; + } + } + else { + const trimmedRole = user.role.toLowerCase(); + const errorMessage: any = `An user with ${"Root " + trimmedRole} role can’t be assigned to ${user.role} role`; + if (roleMap[trimmedRole] && roleMap[trimmedRole]["!sheet#name!"] != user["!sheet#name!"]) { + duplicates.push({ rowNumber: user["!row#number!"], sheetName: user["!sheet#name!"], status: "INVALID", errorDetails: errorMessage }); + } else { + roleMap[trimmedRole] = user; + } + } + } + } + if (duplicates.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...duplicates] : duplicates; +} + +function convertDataSheetWise(userMapping: any) { + const sheetMapping: any = {} + for (const phoneNumber in userMapping) { + const users = userMapping[phoneNumber]; + for (const user of users) { + const sheetName = user["!sheet#name!"]; + if (!sheetMapping[sheetName]) { + sheetMapping[sheetName] = []; + } + sheetMapping[sheetName].push(user); + } + } + return sheetMapping; +} + +function getInconsistencyErrorMessage(phoneNumber: any, userRecords: any) { + // Create the error message mentioning all the records for this phone number + const errors: any = [] + const errorMessage = `User details for the same contact number don't match. Please check the user's name or email ID`; + for (const record of userRecords) { + errors.push({ rowNumber: record.row, sheetName: record.sheet, status: "INVALID", errorDetails: errorMessage }); + } + + return errors +} + +function enrichInconsistencies(overallInconsistencies: any, userMapping: any, nameKey: string, emailKey: string) { + for (const phoneNumber in userMapping) { + if (phoneNumber && phoneNumber != 'undefined') { + const users = userMapping[phoneNumber]; + const userRecords: any[] = []; + + // Collect all user data for this phone number + for (const user of users) { + userRecords.push({ + row: user["!row#number!"], + sheet: user["!sheet#name!"], + name: user[nameKey], + email: user[emailKey] + }); + } + + const errorMessage = getInconsistencyErrorMessage(phoneNumber, userRecords); + + // Check for any inconsistencies by comparing all records with each other + const firstRecord = userRecords[0]; // Take the first record as baseline + const inconsistentRecords = userRecords.filter(record => + record.name !== firstRecord.name || record.email !== firstRecord.email + ); + if (inconsistentRecords.length > 0) { + overallInconsistencies.push(...errorMessage); // Collect all inconsistencies + } + } + } +} + +function lockTillStatus(workbook: any) { + workbook.worksheets.forEach((sheet: any) => { + const statusCell = findStatusColumn(sheet); // Find the status column + + if (!statusCell) { + // Lock the entire sheet if no "#status#" found + sheet.protect('passwordhere', { + selectLockedCells: true, + selectUnlockedCells: false + }); + } else { + // Lock the entire sheet but allow selecting unlocked cells + sheet.protect('passwordhere', { + selectLockedCells: true, + selectUnlockedCells: true // Allow selecting unlocked cells + }); + + // Lock the first row + sheet.getRow(1).eachCell({ includeEmpty: true }, (cell: any) => { + cell.protection = { locked: true }; + }); + + // Lock every column starting from the "#status#" column + const statusColIndex = statusCell.col; + for (let col = statusColIndex; col <= sheet.columnCount; col++) { + sheet.getColumn(col).eachCell({ includeEmpty: true }, (cell: any) => { + cell.protection = { locked: true }; + }); + } + + // Unlock the rest of the sheet (if needed) + sheet.eachRow((row: any, rowIndex: any) => { + if (rowIndex > 1) { // Skip first row + row.eachCell({ includeEmpty: true }, (cell: any) => { + if (cell.col < statusColIndex) { // Unlock cells before the status column + cell.protection = { locked: false }; + } + }); + } + }); + } + }); +} + +export function lockWithConfig(sheet: any) { + for (let row = 1; row <= Number.parseInt(config.values.unfrozeTillRow); row++) { + for (let col = 1; col <= Number.parseInt(config.values.unfrozeTillColumn); col++) { + const cell = sheet.getCell(row, col); + if (!cell.value && cell.value !== 0) { + cell.protection = { locked: false }; + } + } + } + sheet.protect('passwordhere', { selectLockedCells: true, selectUnlockedCells: true }); +} + +function lockAll(workbook: any) { + workbook.worksheets.forEach((sheet: any) => { + lockWithConfig(sheet); + }) +} + + +export function lockSheet(request: any, workbook: any) { + if (request?.body?.ResourceDetails?.type == 'create') { + lockAll(workbook); + } + else { + lockTillStatus(workbook); + } +} + +// Helper function to find the column containing "#status#" +function findStatusColumn(sheet: any) { + let statusCell: any = null; + + // Loop through each row + sheet.eachRow((row: any, rowIndex: any): any => { + // Loop through each cell in the row + row.eachCell((cell: any, colIndex: any) => { + // If "#status#" is found, capture the row and column + if (cell.value === "#status#") { + statusCell = { row: rowIndex, col: colIndex }; + } + }); + + // If the status cell is found, stop further iteration + if (statusCell) { + return false; // This will only break the row loop, not the function + } + }); + + // Return the found statusCell, or null if not found + return statusCell; +} + +export function changeCreateDataForMicroplan(request: any, element: any, rowData: any, localizationMap?: any) { + const type = request?.body?.ResourceDetails?.type; + const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; + if (type == 'facility') { + const projectType = request?.body?.projectTypeCode; + const facilityCapacityColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN_${projectType}`, localizationMap); + if (rowData[facilityCapacityColumn] >= 0) { + element.storageCapacity = rowData[facilityCapacityColumn] + } + if (activeColumnName && rowData[activeColumnName] == "Active") { + if (Array(request?.body?.facilityDataForMicroplan) && request?.body?.facilityDataForMicroplan?.length > 0) { + request.body.facilityDataForMicroplan.push({ ...rowData, facilityDetails: element }) + } + else { + request.body.facilityDataForMicroplan = [{ ...rowData, facilityDetails: element }] + } + } + } +} + +export function updateFacilityDetailsForMicroplan(request: any, createdData: any) { + const facilityDataForMicroplan = request?.body?.facilityDataForMicroplan; + if (Array.isArray(facilityDataForMicroplan) && facilityDataForMicroplan.length > 0) { + for (const element of facilityDataForMicroplan) { + const rowNumber = element['!row#number!']; + const createdDataWithMatchingRowNumber = createdData.find((data: any) => data['!row#number!'] == rowNumber) || null; + if (createdDataWithMatchingRowNumber) { + element.facilityDetails.id = createdDataWithMatchingRowNumber.id + } + } + } +} + + +export async function createPlanFacilityForMicroplan(request: any, localizationMap?: any) { + if (request?.body?.ResourceDetails?.type == 'facility' && request?.body?.ResourceDetails?.additionalDetails?.source == 'microplan') { + const allFacilityDatas = request?.body?.facilityDataForMicroplan; + const planConfigurationId = request?.body?.ResourceDetails?.additionalDetails?.microplanId; + request.body.MicroplanDetails = { + tenantId: request?.body?.ResourceDetails?.tenantId, + planConfigurationId: planConfigurationId + } + const planConfigSearchResponse = await planConfigSearch(request); + const planConfigurationName = planConfigSearchResponse?.PlanConfiguration?.[0]?.name; + for (const element of allFacilityDatas) { + const produceObject: any = getPlanFacilityObject(request, element, planConfigurationName, planConfigurationId, localizationMap); + await produceModifiedMessages(produceObject, config?.kafka?.KAFKA_SAVE_PLAN_FACILITY_TOPIC); + } + } +} + +function getPlanFacilityObject(request: any, element: any, planConfigurationName: any, planConfigurationId: any, localizationMap?: any) { + const residingBoundariesColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN`, localizationMap); + const singularResidingBoundary = element?.[residingBoundariesColumn] + ? element[residingBoundariesColumn].split(",")[0] + : null; + const facilityStatus = element?.facilityDetails?.isPermanent ? "Permanent" : "Temporary"; + const facilityType = element?.facilityDetails?.usage; + const hierarchyType = request?.body?.ResourceDetails?.hierarchyType; + const currTime = new Date().getTime(); + const planFacilityProduceObject: any = { + PlanFacility: { + id: uuidv4(), + tenantId: element?.facilityDetails?.tenantId, + planConfigurationId: planConfigurationId, + facilityId: element?.facilityDetails?.id, + residingBoundary: singularResidingBoundary, + facilityName: element?.facilityDetails?.name, + serviceBoundaries: null, + planConfigurationName: planConfigurationName, + additionalDetails: { + capacity: element?.facilityDetails?.storageCapacity, + facilityName: element?.facilityDetails?.name, + facilityType: facilityType, + facilityStatus: facilityStatus, + assignedVillages: [], + servingPopulation: 0, + hierarchyType: hierarchyType + }, + active: true, + auditDetails: { + createdBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + createdTime: currTime, + lastModifiedTime: currTime + } + } + } + const fixedPostColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_FACILITY_FIXED_POST_MICROPLAN`, localizationMap); + if (element?.[fixedPostColumn]) { + planFacilityProduceObject.PlanFacility.additionalDetails.fixedPost = element?.[fixedPostColumn] + } + return planFacilityProduceObject; +} + + +export async function planFacilitySearch(request: any) { + const { tenantId, planConfigurationId } = request.body.MicroplanDetails; + const searchBody = { + RequestInfo: request.body.RequestInfo, + PlanFacilitySearchCriteria: { + tenantId: tenantId, + planConfigurationId: planConfigurationId + } + } + + const searchResponse = await httpRequest(config.host.planServiceHost + config.paths.planFacilitySearch, searchBody); + return searchResponse; +} + +export function planConfigSearch(request: any) { + const { tenantId, planConfigurationId } = request.body.MicroplanDetails; + const searchBody = { + RequestInfo: request.body.RequestInfo, + PlanConfigurationSearchCriteria: { + tenantId: tenantId, + id: planConfigurationId + } + } + + const searchResponse = httpRequest(config.host.planServiceHost + config.paths.planConfigSearch, searchBody); + return searchResponse; +} + +export function modifyBoundaryIfSourceMicroplan(boundaryData: any[], request: any) { + // Check if the request is for a source microplan and the type is 'facilityWithBoundary' + if (request?.body?.isSourceMicroplan && request?.query?.type == 'facilityWithBoundary') { + // Extract the boundary hierarchy from the request body + const hierarchy = request?.body?.hierarchyType?.boundaryHierarchy; + let villageIndex: any; + // Determine the `villageIndex` based on the hierarchy length if present + if (hierarchy) { + // Set `villageIndex` to the last element in the hierarchy (boundary hierarchy depth) + villageIndex = hierarchy?.length - 1; + } else { + // If no hierarchy is provided, calculate the `villageIndex` dynamically + let maxBoundaryDataLength = 0; + + // Iterate through `boundaryData` to find the maximum length of any boundary array + for (const boundary of boundaryData) { + if (boundary?.length > maxBoundaryDataLength) { + maxBoundaryDataLength = boundary?.length; + } + } + + // If boundary data has sufficient depth, set `villageIndex` to the second-to-last level + if (maxBoundaryDataLength >= 2) { + villageIndex = maxBoundaryDataLength - 2; + } + } + // Filter out boundaries that don't have the `villageIndex` + boundaryData = boundaryData.filter((boundary: any) => boundary?.[villageIndex]); + } + return boundaryData; +} + +export async function getRolesForMicroplan(tenantId: string, localizationMap: any, fetchWithRoleCodes: boolean = false) { + const MdmsCriteria: any = { + tenantId: tenantId, + schemaCode: "hcm-microplanning.rolesForMicroplan", + }; + const mdmsResponse: any = await searchMDMSDataViaV2Api(MdmsCriteria); + if (mdmsResponse?.mdms?.length > 0) { + if (fetchWithRoleCodes) { + // return array { role : "role", code : "roleCode" } + return mdmsResponse?.mdms?.filter((role: any) => role?.isActive) + ?.map((role: any) => ({ role: getLocalizedName(role?.data?.roleCode, localizationMap), code: role?.data?.roleCode })); + } + else { + return mdmsResponse?.mdms + ?.filter((role: any) => role?.isActive) // Filter roles with isActive true + ?.map((role: any) => getLocalizedName(role?.data?.roleCode, localizationMap)); // Map to extract the role + } + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", `Some error occured during rolesForMicroplan mdms search.`); + return []; + } +} + +export async function isMicroplanRequest(request: any): Promise { + const campaignId = request?.query?.campaignId || request?.body?.ResourceDetails?.campaignId; + if (campaignId == "microplan") { + return true; + } + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + return checkIfSourceIsMicroplan(campaignObject); +} + +export async function getReadMeConfigForMicroplan(request: any) { + const mdmsResponse = await callMdmsData(request, "HCM-ADMIN-CONSOLE", "ReadMeConfig", request?.query?.tenantId); + if (mdmsResponse?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig) { + const readMeConfigsArray = mdmsResponse?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig + for (const readMeConfig of readMeConfigsArray) { + if (readMeConfig?.type == `${request?.query?.type}_MICROPLAN`) { + return readMeConfig + } + } + throwError("MDMS", 500, "INVALID_README_CONFIG", `Readme config for type ${request?.query?.type} not found.`); + return {} + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", `Some error occured during readme config mdms search.`); + return {}; + } +} + diff --git a/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts b/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts new file mode 100644 index 00000000000..1f4894c43b7 --- /dev/null +++ b/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts @@ -0,0 +1,781 @@ +import { searchProjectTypeCampaignService } from "../service/campaignManageService"; +import { getLocalizedHeaders, replicateRequest, throwError } from "./genericUtils"; +import { httpRequest } from "./request"; +import config from "../config/index"; +import { getLocalizedName } from "./campaignUtils"; +import { logger } from "./logger"; +import { callGenerate } from "./generateUtils"; +// import { getCampaignSearchResponse } from "server/api/campaignApis"; +import { getExcelWorkbookFromFileURL } from "./excelUtils"; +import { createAndUploadFile, getSheetData, getTargetSheetData } from "../api/genericApis"; +import { searchDataService } from "../service/dataManageService"; +import { produceModifiedMessages } from "../kafka/Producer"; + +async function getParentCampaignObject(request: any, parentId: any) { + try { + // const searchBodyForParent = { + // RequestInfo: request.body.RequestInfo, + const CampaignDetails = { + tenantId: request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId || request?.body?.CampaignDetails?.tenantId, + ids: [parentId] + } + // }; + // const req: any = replicateRequest(request, searchBodyForParent); + const parentSearchResponse = await searchProjectTypeCampaignService(CampaignDetails); + return parentSearchResponse?.CampaignDetails?.[0]; + } catch (error) { + logger.error("Error fetching parent campaign object:", error); + throwError("CAMPAIGN", 400, "PARENT_CAMPAIGN_ERROR", "Parent Campaign fetching error "); + } +} + +function getCreatedResourceIds(resources: any, type: any) { + const processedType = type === 'boundary' + ? 'boundaryWithTarget' + : (type.includes('With') ? type.split('With')[0] : type); + return resources + .filter((item: any) => item.type === processedType) + .map((item: any) => item.createResourceId); +} + +function buildSearchCriteria(request: any, createdResourceId: any, type: any) { + const processedType = type === 'boundary' + ? 'boundaryWithTarget' + : (type === 'boundaryWithTarget' ? type : (type.includes('With') ? type.split('With')[0] : type)); + + const requestInfo = request?.body + ? request.body.RequestInfo + : { RequestInfo: request?.RequestInfo }; + return { + RequestInfo: requestInfo, + SearchCriteria: { + id: createdResourceId, + tenantId: request?.query?.tenantId || request?.CampaignDetails?.tenantId, + type: processedType + } + }; +} + +async function fetchFileUrls(request: any, processedFileStoreIdForUSerOrFacility: any) { + try { + const reqParamsForFetchingFile = { + tenantId: request?.query?.tenantId, + fileStoreIds: processedFileStoreIdForUSerOrFacility + }; + return await httpRequest( + `${config?.host?.filestore}${config?.paths?.filestorefetch}`, + request?.body, + reqParamsForFetchingFile, + "get" + ); + } catch (error) { + logger.error("Error fetching file URLs:", error); + throw error; + } +} + + + +function modifyProcessedSheetData(request: any, sheetData: any, localizationMap?: any) { + // const type = request?.query?.type || request?.body?.ResourceDetails?.type; + // const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; + if (!sheetData || sheetData.length === 0) return []; + + // Find the row with the maximum number of keys + const maxLengthRow = sheetData.reduce((maxRow: any, row: any) => { + return Object.keys(row).length > Object.keys(maxRow).length ? row : maxRow; + }, {}); + + // Extract headers from the keys of the row with the maximum number of keys + const originalHeaders = Object.keys(maxLengthRow); + const statusIndex = originalHeaders.indexOf('#status#'); + // Insert 'errordetails' after '#status#' if found + if (statusIndex !== -1) { + originalHeaders.splice(statusIndex + 1, 0, '#errorDetails#'); + } + + let localizedHeaders = getLocalizedHeaders(originalHeaders, localizationMap); + + // Map each object in sheetData to an array of values corresponding to the header order + let dataRows = sheetData.map((row: any) => { + return localizedHeaders.map((header: any) => row[header] || ''); + }); + + const updatedHeaders = localizedHeaders.map((header: any) => header === getLocalizedName(config?.boundary?.boundaryCodeMandatory, localizationMap) ? + getLocalizedName(config?.boundary?.boundaryCodeOld, localizationMap) : header) + + const updatedWithAdditionalHeaders = [...updatedHeaders, config?.boundary?.boundaryCodeMandatory] + localizedHeaders = getLocalizedHeaders(updatedWithAdditionalHeaders, localizationMap); + + dataRows = dataRows.map((row: any, index: number) => { + const boundaryCodeValue = sheetData[index][getLocalizedName(config?.boundary?.boundaryCodeMandatory, localizationMap)] || ''; + return [...row, boundaryCodeValue]; + }); + + // Combine headers and dataRows + const modifiedData = [localizedHeaders, ...dataRows]; + + return modifiedData; +} + +function freezeUnfreezeColumnsForProcessedFile(sheet: any, columnsToFreeze: number[], columnsToUnfreeze: number[]) { + // First, unfreeze specified columns + columnsToUnfreeze.forEach(colNumber => { + for (let row = 1; row <= sheet.rowCount; row++) { + const cell = sheet.getCell(row, colNumber); + cell.protection = { locked: false }; // Unfreeze the cell + } + }); + + // Then, freeze specified columns + columnsToFreeze.forEach(colNumber => { + for (let row = 1; row <= sheet.rowCount; row++) { + const cell = sheet.getCell(row, colNumber); + cell.protection = { locked: true }; // Freeze the cell + } + }); +} + + +function getColumnIndexByHeader(sheet: any, headerName: string): number { + // Get the first row (assumed to be the header row) + const firstRow = sheet.getRow(1); + + // Find the column index where the header matches the provided name + for (let col = 1; col <= firstRow.cellCount; col++) { + const cell = firstRow.getCell(col); + if (cell.value === headerName) { + return col; // Return the column index (1-based) + } + } + return 1; +} + +// function validateBoundaryCodes(activeRows: any, localizationMap?: any) { +// const updatedBoundaryCodeKey = getLocalizedName('HCM_ADMIN_CONSOLE_UPDATED_BOUNDARY_CODE', localizationMap); +// const updatedBoundaryCodeValue = activeRows[updatedBoundaryCodeKey]; +// const boundaryCodeMandatoryKey = getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", localizationMap); +// const boundaryCodeMandatoryValue = activeRows[boundaryCodeMandatoryKey]; +// if (!updatedBoundaryCodeValue && !boundaryCodeMandatoryValue) { +// const errorDetails = { +// errors: [ +// { +// instancePath: '', +// schemaPath: '#/required', +// keyword: 'required', +// params: { +// missingProperty: `${updatedBoundaryCodeKey} and ${boundaryCodeMandatoryKey} both` +// }, +// message: `must have required properties ${`${updatedBoundaryCodeKey}, ${boundaryCodeMandatoryKey}`}` +// } +// ] +// }; + +// throw new Error(JSON.stringify(errorDetails)); +// } +// } + +async function checkAndGiveIfParentCampaignAvailable(request: any, campaignObject: any) { + if (campaignObject?.parentId) { + logger.info("enriching the parent campaign details for update flow"); + const parentCampaignObject = await getParentCampaignObject(request, campaignObject.parentId); + + if (parentCampaignObject?.status === "created" && !parentCampaignObject.isActive) { + request.body.parentCampaignObject = parentCampaignObject; + } + } +} + +function hideColumnsOfProcessedFile(sheet: any, columnsToHide: any[]) { + columnsToHide.forEach((column) => { + if (column > 0) { + sheet.getColumn(column).hidden = true; + } + }); +} + +function unhideColumnsOfProcessedFile(sheet: any, columnsToUnide: any) { + columnsToUnide.forEach((column: any) => { + if (column) { + sheet.getColumn(column).hidden = false; + } + }); +} + +function modifyNewSheetData(processedDistrictSheetData: any, newSheetData: any, headers: any, oldTargetColumnsToHide: any[], localizationMap?: any) { + let modifiedData = []; + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + if (processedDistrictSheetData && processedDistrictSheetData.length > 0) { + const dataRows = processedDistrictSheetData.map((row: any) => { + return localizedHeaders.map((header: any) => row[header] || ''); + }); + modifiedData = [localizedHeaders, ...dataRows]; + } else { + // If processedDistrictSheetData is not present, work only with newSheetData + modifiedData = [newSheetData]; + } + + const newData = updateTargetValues(modifiedData, newSheetData, localizedHeaders, oldTargetColumnsToHide, localizationMap); + return newData; +} + + +function updateTargetValues(originalData: any, newData: any, localizedHeaders: any, oldTargetColumnsToHide: any[], localizationMap?: any) { + + const boundaryCodeIndex = localizedHeaders.indexOf(getLocalizedName(config?.boundary?.boundaryCode, localizationMap)); + + // Update newData with matching values from originalData + newData = newData.map((newRow: any) => { + const matchingRow = originalData.find((originalRow: any) => + originalRow.slice(0, boundaryCodeIndex + 1).every((val: any, index: any) => val === newRow[index]) + ); + + return newRow.map((value: any, index: any) => + index > boundaryCodeIndex && matchingRow && value === '' + ? matchingRow[index] + : value + ); + }); + newData = newData.map((newRow: any, rowIndex: number) => { + const updatedValues: any[] = []; + for (let i = boundaryCodeIndex + 1; i < localizedHeaders.length; i++) { + updatedValues.push(newRow[i]); // Store original value + if (rowIndex === 0) { // Only modify the first row + const modifiedValue = `${newRow[i]}(OLD)`; // Create modified value with (OLD) suffix + newRow[i] = modifiedValue; // Update newRow[i] with the modified value + oldTargetColumnsToHide.push(modifiedValue); // Push the modified value + } + } + // Concatenate original values at the end of every row + return [...newRow, ...updatedValues]; + }); + return newData; +} + +function validateBoundariesIfParentPresent(request: any) { + const { parentCampaign, CampaignDetails } = request?.body || {}; + + if (parentCampaign) { + const errors: string[] = []; + const newBoundaries: any[] = []; + const parentCampaignBoundaryCodes = parentCampaign.boundaries.map((boundary: any) => boundary.code); + + CampaignDetails?.boundaries?.forEach((boundary: any) => { + if (parentCampaignBoundaryCodes.includes(boundary.code)) { + errors.push(boundary.code); + } else { + if (!boundary?.isRoot) { + newBoundaries.push(boundary); + } else { + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `Boundary with code ${boundary.code} cannot be added as it is marked as root. Root boundary should come from the parent campaign.` + ); + } + } + }); + + if (errors.length > 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Codes found already in Parent Campaign: ${errors.join(', ')}`); + } + request.body.boundariesCombined = [...parentCampaign.boundaries, ...newBoundaries]; + } + else { + request.body.boundariesCombined = request?.body?.CampaignDetails?.boundaries + } +} + + +async function callGenerateWhenChildCampaigngetsCreated(request: any) { + try { + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, + Filters: { + boundaries: request?.body?.boundariesCombined + } + }; + + const { query } = request; + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + forceUpdate: 'true', + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + campaignId: request?.body?.CampaignDetails?.id + }; + + const newParamsBoundary = { ...query, ...params, type: "boundary" }; + const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); + await callGenerate(newRequestBoundary, "boundary"); + + const newParamsFacilityWithBoundary = { ...query, ...params, type: "facilityWithBoundary" }; + const newRequestFacilityWithBoundary = replicateRequest(request, newRequestBody, newParamsFacilityWithBoundary); + await callGenerate(newRequestFacilityWithBoundary, "facilityWithBoundary"); + + const newParamsUserWithBoundary = { ...query, ...params, type: "userWithBoundary" }; + const newRequestUserWithBoundary = replicateRequest(request, newRequestBody, newParamsUserWithBoundary); + await callGenerate(newRequestUserWithBoundary, "userWithBoundary"); + } + catch (error: any) { + logger.error(error); + throwError("COMMON", 400, "GENERATE_ERROR", `Error while generating user/facility/boundary: ${error.message}`); + } +} + + +function getBoundariesArray(parentCampaignBoundaries: any, campaignBoundaries: any) { + // Ensure both inputs are arrays or default to empty arrays + const validParentBoundaries = Array.isArray(parentCampaignBoundaries) ? parentCampaignBoundaries : []; + const validCampaignBoundaries = Array.isArray(campaignBoundaries) ? campaignBoundaries : []; + + return [...validParentBoundaries, ...validCampaignBoundaries]; +} + +async function getBoundariesFromCampaignSearchResponse(request: any, campaignDetails: any) { + let parentCampaignBoundaries: any[] = []; + if (campaignDetails?.parentId) { + const parentCampaignObject = await getParentCampaignObject(request, campaignDetails?.parentId); + parentCampaignBoundaries = parentCampaignObject?.boundaries; + } + return getBoundariesArray(parentCampaignBoundaries, campaignDetails?.boundaries) +} + +async function fetchProjectsWithProjectId(request: any, projectId: any, tenantId: any) { + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo || request?.RequestInfo, + Projects: [ + { + id: projectId, + tenantId: tenantId + } + ] + } + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1, + includeDescendants: true + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + const projectSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectSearch, projectSearchBody, projectSearchParams); + if (projectSearchResponse?.Project && Array.isArray(projectSearchResponse?.Project) && projectSearchResponse?.Project?.length > 0) { + return projectSearchResponse; + } + else { + throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR") + return [] + } +} + + +async function fetchProjectsWithBoundaryCodeAndReferenceId(boundaryCode: any, tenantId: any, referenceId: any, RequestInfo?: any) { + try { + const projectSearchBody = { + RequestInfo: RequestInfo, + Projects: [ + { + address: { + boundary: boundaryCode, + }, + tenantId: tenantId, + referenceID: referenceId + } + ] + } + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1 + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + const projectSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectSearch, projectSearchBody, projectSearchParams); + if (projectSearchResponse?.Project && Array.isArray(projectSearchResponse?.Project) && projectSearchResponse?.Project?.length > 0) { + return projectSearchResponse; + } + else { + return null; + } + } catch (error: any) { + throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR") + } +} + +function getBoundaryProjectMappingFromParentCampaign(request: any, project: any) { + + const boundarySet = new Set(); + + // Initialize result array with the project itself (id and boundary) + const result = [ + { + id: project.id, + boundary: project.address.boundary + }, + ...project.descendants.map((descendant: any) => ({ + id: descendant.id, + boundary: descendant.address.boundary + })) + ]; + + // Iterate over the result array to find matching boundaries and populate projectId + result.forEach((entry: any) => { + const boundary = entry.boundary; + boundarySet.add(boundary); + // Initialize the boundaryProjectMapping for this boundary if not present + if (!request?.body?.boundaryProjectMapping?.[boundary]) { + request.body.boundaryProjectMapping[boundary] = { parent: null, projectId: null }; + } + // Update the projectId in the request's boundaryProjectMapping + request.body.boundaryProjectMapping[boundary].projectId = entry.id; + }); + + return boundarySet; +} + + +async function fetchProjectFacilityWithProjectId(request: any, projectId: any, facilityId: any) { + try { + const { tenantId } = request?.body?.parentCampaign || request?.parentCampaign; + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo || request?.RequestInfo, + ProjectFacility: { + projectId: [ + projectId + ], + facilityId: [ + facilityId + ] + } + } + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1 + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + const projectFacilitySearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectFacilitySearch, projectSearchBody, projectSearchParams); + + if (projectFacilitySearchResponse?.ProjectFacilities && Array.isArray(projectFacilitySearchResponse?.ProjectFacilities) && projectFacilitySearchResponse?.ProjectFacilities?.length > 0) { + return projectFacilitySearchResponse; + } + else { + return null + } + } catch (error: any) { + throwError("PROJECT", 500, "PROJECT_FACILTY_SEARCH_ERROR") + } +} + + +async function fetchProjectStaffWithProjectId(request: any, projectId: any, staffId: any) { + try { + const { tenantId } = request?.body?.parentCampaign || request?.parentCampaign; + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo || request?.RequestInfo, + ProjectStaff: { + projectId: [ + projectId + ], + staffId: [ + staffId + ] + } + } + + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1 + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + const projectStaffSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectStaffSearch, projectSearchBody, projectSearchParams); + if (projectStaffSearchResponse?.ProjectStaff && Array.isArray(projectStaffSearchResponse?.ProjectStaff) && projectStaffSearchResponse?.ProjectStaff?.length > 0) { + return projectStaffSearchResponse; + } + else { + return null + } + } catch (error: any) { + throwError("PROJECT", 500, "PROJECT_STAFF_SEARCH_ERROR") + } + +} + +async function delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary(resource: any, messageObject: any, boundaryCode: any, uniqueIdentifier: any, isDelink: boolean) { + const projectResponse = await fetchProjectsWithBoundaryCodeAndReferenceId(boundaryCode, messageObject?.parentCampaign?.tenantId, messageObject?.CampaignDetails?.campaignNumber, messageObject?.RequestInfo); + let matchingProjectObject: any; + if (projectResponse) { + matchingProjectObject = projectResponse?.Project[0]; + } + const matchingProjectId = matchingProjectObject?.id; + if (!matchingProjectId) { + return false; // No matching project found + } + + + if (resource?.type === "facility") { + const projectFacilityResponse = await fetchProjectFacilityWithProjectId(messageObject, matchingProjectId, uniqueIdentifier); + if (projectFacilityResponse) { + if (isDelink) { + await deleteProjectFacilityMapping(messageObject, projectFacilityResponse) + } + return true; + } else { + return false; + } + } + if (resource?.type === 'user') { + const projectStaffResponse = await fetchProjectStaffWithProjectId(messageObject, matchingProjectId, uniqueIdentifier); + if (projectStaffResponse) { + if (isDelink) { + await deleteProjectStaffMapping(messageObject, projectStaffResponse) + } + return true; + } else { + return false; + } + } + else return false; +} + + +async function deleteProjectFacilityMapping(messageObject: any, projectFacilityResponse: any) { + const projectFacilityDeleteBody = { + RequestInfo: messageObject?.RequestInfo, + ProjectFacilities: [ + projectFacilityResponse?.ProjectFacilities[0] + ] + } + try { + await httpRequest(config?.host?.projectHost + config?.paths?.projectFacilityDelete, projectFacilityDeleteBody); + } + catch (error: any) { + throwError("PROJECT", 500, "PROJECT_FACILITY_DELETE_ERROR") + } +} + +async function deleteProjectStaffMapping(messageObject: any, projectStaffResponse: any) { + const projectStaffDeleteBody = { + RequestInfo: messageObject?.RequestInfo, + ProjectStaff: [ + projectStaffResponse?.ProjectStaff[0] + ] + } + try { + await httpRequest(config?.host?.projectHost + config?.paths?.projectStaffDelete, projectStaffDeleteBody); + } + catch (error: any) { + throwError("PROJECT", 500, "PROJECT_STAFF_DELETE_ERROR") + } +} + + +async function getParentAndCurrentFileUrl(mappingObject: any, resource: any, parentResource: any) { + const parentCreateResourceId = parentResource?.createResourceId ? [parentResource.createResourceId] : []; + const parentResourceSearchResponse = await getResourceFromResourceId(mappingObject, parentCreateResourceId, parentResource); + const parentProcessedFileStoreId = parentResourceSearchResponse?.[0]?.processedFilestoreId; + + const currentCreateResourceId = resource?.createResourceId ? [resource.createResourceId] : []; + const currentResourceSearchResponse = await getResourceFromResourceId(mappingObject, currentCreateResourceId, resource); + const currentProcessedFileStoreId = currentResourceSearchResponse?.[0]?.processedFilestoreId; + + const currentFileUrl = await getFileUrl(currentProcessedFileStoreId, mappingObject?.CampaignDetails?.tenantId); + const parentFileUrl = await getFileUrl(parentProcessedFileStoreId, mappingObject?.CampaignDetails?.tenantId); + + return { currentFileUrl, parentFileUrl }; +} + +function findParentResource(resource: any, resourcesArrayFromParentCampaign: any) { + return resourcesArrayFromParentCampaign.find( + (parentResource: any) => parentResource.type === resource.type + ); +} + +async function getHeadersAccordingToWhichWeReorder(parentWorkbook: any, resource: any) { + + // Determine the sheet name dynamically based on resource type + const headerSourceSheetName: any = resource?.type === 'boundaryWithTarget' + ? parentWorkbook.worksheets[2]?.name // Use the third sheet for 'boundaryWithTarget' type + : parentWorkbook.worksheets[1]?.name; // Use the second sheet for other types + + const sheet = parentWorkbook.getWorksheet(headerSourceSheetName); + if (!sheet) { + throw new Error(`Sheet with name "${headerSourceSheetName}" not found`); + } + + // Get the first row (assuming it's the header row) + const headerRow = sheet.getRow(1); + // Get the first row (assuming it's the header row) + if (!headerRow || headerRow.cellCount === 0) { + throw new Error(`Header row is empty in sheet "${headerSourceSheetName}"`); + } + const headers: any = []; + + headerRow.eachCell((cell: any) => { + headers.push(cell.value); // Collect header cell values + }); + + return headers; +} + + + +async function addDataToWorkbook(currentWorkbook: any, parentWorkbook: any, currentFileUrl: any, resource: any, headersAccordingToWhichWeReorder: any) { + const currentSheet = currentWorkbook.worksheets[1]; + if (resource?.type === 'boundaryWithTarget') { + const boundaryWithTargetSheetData = await getTargetSheetData(currentFileUrl, false, false); + const sheetNames = Object.keys(boundaryWithTargetSheetData); // Get sheet names + for (let i = 2; i < sheetNames.length; i++) { // Start from index 2 for the third sheet + const sheetName = sheetNames[i]; + const sheetData = boundaryWithTargetSheetData[sheetName]; + + // Reorder each row in the current sheet's data + const reorderedData = sheetData.map((row: any) => { + // Map each header in `targetHeaders` to the corresponding value in `row`, + // or set to an empty string if the header is missing + return headersAccordingToWhichWeReorder.map((header: any) => row[header] || ""); + }); + + await addConsolidatedDataToSheet(parentWorkbook, sheetName, headersAccordingToWhichWeReorder, reorderedData); + } + } else { + // Perform further processing using the filestoreId + const currentSheetData: any = await getSheetData(currentFileUrl, currentSheet.name, false) + + const reorderedData = currentSheetData.map((row: any) => { + // Map each header in `targetHeaders` to the corresponding value in the row, + // or set to an empty string if the header is missing in the row + return headersAccordingToWhichWeReorder.map((header: any) => row[header] || ""); + }); + + await addConsolidatedDataToSheet(parentWorkbook, currentSheet.name, headersAccordingToWhichWeReorder, reorderedData); + } +} + + +async function finalizeAndUpload(newWorkbook: any, mappingObject: any, resource: any) { + const responseData = await createAndUploadFile(newWorkbook, mappingObject, mappingObject?.CampaignDetails?.tenantId); + const fileStoreId = responseData?.[0]?.fileStoreId; + const resourceDetails = (await getResourceFromResourceId(mappingObject, [resource.createResourceId], resource))[0]; + resourceDetails.processedFilestoreId = fileStoreId; + resourceDetails.processedFileStoreId = resourceDetails.processedFilestoreId; + resourceDetails.processedFilestoreId = undefined; + + const persistMessage: any = { ResourceDetails: resourceDetails }; + await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); +} + + + + +async function processIndividualResource(mappingObject: any, resource: any, resourcesArrayFromParentCampaign: any) { + const parentResource = findParentResource(resource, resourcesArrayFromParentCampaign); + const fileUrls = await getParentAndCurrentFileUrl(mappingObject, resource, parentResource); + + const parentWorkbook = await getExcelWorkbookFromFileURL(fileUrls.parentFileUrl); + const currentWorkbook = await getExcelWorkbookFromFileURL(fileUrls.currentFileUrl) + + const headersAccordingToWhichWeReorder = await getHeadersAccordingToWhichWeReorder(parentWorkbook, resource); + await addDataToWorkbook(currentWorkbook, parentWorkbook, fileUrls?.currentFileUrl, resource, headersAccordingToWhichWeReorder); + + await finalizeAndUpload(parentWorkbook, mappingObject, resource); +} + + +function mergeParentResources(mappingObject: any, resources: any[], resourcesArrayFromParentCampaign: any[]) { + for (const resource of resourcesArrayFromParentCampaign) { + if (!resources.some((r: any) => r.type === resource.type)) { + resources.push(resource); + } + } + mappingObject.CampaignDetails.campaignDetails.resources = resources; +} + +async function processResources(mappingObject: any) { + + const resources = mappingObject?.CampaignDetails?.resources; + const resourcesArrayFromParentCampaign = mappingObject?.parentCampaign?.resources; + + for (const resource of resources) { + try { + await processIndividualResource(mappingObject, resource, resourcesArrayFromParentCampaign); + } catch (error: any) { + throwError("CAMPAIGN", 500, "RESOURCES_CONSOLIDATION_ERROR", + `Error occurred while consolidating resource of type ${resource.type}: ${error.message}`); + } + } + + mergeParentResources(mappingObject, resources, resourcesArrayFromParentCampaign); +} + +async function getResourceFromResourceId(mappingObject: any, createResourceId: any, resource: any) { + const searchCriteria = buildSearchCriteria(mappingObject, createResourceId, resource?.type); + const requestBody = replicateRequest(mappingObject, searchCriteria); + const responseFromDataSearch = await searchDataService(requestBody); + return responseFromDataSearch; +} + + +async function addConsolidatedDataToSheet(parentWorkbook: any, sheetName: string, targetHeaders: string[], reorderedData: any[]) { + // Get or create a worksheet + let sheet = parentWorkbook.getWorksheet(sheetName); + if (!sheet) { + sheet = parentWorkbook.addWorksheet(sheetName); + sheet.addRow(targetHeaders); + } + if (sheet.rowCount > 1) { + // Clear all existing row data starting from the second row + for (let i = 2; i <= sheet.rowCount; i++) { + sheet.getRow(i).values = []; + } + } + + // Overwrite cleared rows with new data + reorderedData.forEach((row, index) => { + const targetRow = sheet.getRow(index + 2); // Start from the second row + targetRow.values = row; // Add the row's values + }); + +} + + +async function getFileUrl(fileStoreId: any, tenantId: any) { + const fileResponse = await httpRequest( + `${config.host.filestore}${config.paths.filestore}/url`, + {}, + { tenantId, fileStoreIds: fileStoreId }, + "get" + ); + + if (!fileResponse || !fileResponse.fileStoreIds || !fileResponse.fileStoreIds[0] || !fileResponse.fileStoreIds[0].url) { + throwError("FILE", 400, "INVALID_FILE"); + } else { + return fileResponse.fileStoreIds[0].url; + } +} + + + + +export { + getParentCampaignObject, + getCreatedResourceIds, + buildSearchCriteria, + fetchFileUrls, + modifyProcessedSheetData, + freezeUnfreezeColumnsForProcessedFile, + getColumnIndexByHeader, + checkAndGiveIfParentCampaignAvailable, + hideColumnsOfProcessedFile, + unhideColumnsOfProcessedFile, + modifyNewSheetData, + validateBoundariesIfParentPresent, + callGenerateWhenChildCampaigngetsCreated, + getBoundariesFromCampaignSearchResponse, + fetchProjectsWithProjectId, + getBoundaryProjectMappingFromParentCampaign, + fetchProjectFacilityWithProjectId, + fetchProjectsWithBoundaryCodeAndReferenceId, + delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary, + processResources +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/pollUtils.ts b/health-services/project-factory/src/server/utils/pollUtils.ts new file mode 100644 index 00000000000..afba8042988 --- /dev/null +++ b/health-services/project-factory/src/server/utils/pollUtils.ts @@ -0,0 +1,193 @@ +import { defaultRequestInfo } from "../api/coreApis"; // Import default request metadata +import { getFormattedStringForDebug, logger } from "./logger"; // Import logger for logging information and errors +import { createDataService, downloadDataService, searchDataService } from "../service/dataManageService"; +import { throwError } from "./genericUtils"; + +/** + * Downloads a campaign template based on campaign ID, tenant ID, type, and hierarchy. + * @param campaignId The unique identifier for the campaign. + * @param tenantId The tenant identifier for which the template is downloaded. + * @param type The type of the template to be downloaded. + * @param hierarchy The hierarchy type associated with the campaign. + * @returns The response containing the template download details. + */ +export const downloadTemplate = async ( + campaignId: string, + tenantId: string, + type: string, + hierarchy: string +) => { + const searchBody = { + ...defaultRequestInfo, // Include default request metadata + }; + + const params = { + tenantId: tenantId, // Tenant information for the request + type: type, // Specify the template type + hierarchyType: hierarchy, // Specify the hierarchy type + campaignId: campaignId, // Campaign identifier + }; + + logger.info( + `Received a request to download the template for campaign ID: ${campaignId} & type: ${type} ` + ); + const request: any = { + body: { ...searchBody }, + query: { ...params } + } + + const downloadResponse: any = await downloadDataService(request); + + logger.debug(`Received response : ${getFormattedStringForDebug(downloadResponse)}`); + return downloadResponse; // Return the API response containing template details +}; + +/** + * Polls a function at regular intervals until a condition is met or the maximum retries are reached. + * @param functionToBePolledFor The function to be executed for polling. + * @param conditionForTermination A callback function that evaluates whether polling should stop. + * @param pollInterval The interval (in milliseconds) between each poll attempt. Default is 2000ms. + * @param maxRetries The maximum number of retries before terminating polling. Default is 50. + * @returns A promise that resolves with the function response if the condition is met, or rejects if retries are exhausted. + */ +const pollForTemplateGeneration = async ( + functionToBePolledFor: Function, + conditionForTermination: Function, + pollInterval: number = 2500, + maxRetries: number = 20 +) => { + let retries = 0; // Initialize the retry counter + logger.info("received a request for Polling "); + if (!functionToBePolledFor || !conditionForTermination) { + return null; + } + logger.info("request was valid so Polling "); + + return new Promise((resolve, reject) => { + const poll = async () => { + try { + if (retries >= maxRetries) { + // Reject if maximum retries are reached + reject(new Error("Max retries reached")); + return; + } + + const functionResponse = await functionToBePolledFor(); // Execute the polling function + + if (conditionForTermination(functionResponse)) { + // Check if the termination condition is met + logger.info("Polling completed"); + resolve(functionResponse); + return; + } else { + // Increment retries and continue polling after the specified interval + retries++; + logger.info("Polling continuing"); + setTimeout(poll, pollInterval); + } + } catch (error) { + // Handle errors by retrying after the specified interval + retries++; + setTimeout(poll, pollInterval); + } + }; + + // Start polling + poll().catch(reject); + + // Set a timeout to ensure the entire polling operation doesn't exceed a maximum duration + const timeoutDuration = (maxRetries + 1) * pollInterval; + setTimeout(() => { + if (retries < maxRetries) { + logger.error("Polling timeout: Max retries reached"); + reject(new Error("Polling timeout: Max retries reached")); + } + }, timeoutDuration); + }); +}; + + + +const conditionForTermination = (downloadResponse: any) => { + logger.info(`current status ${downloadResponse?.[0]?.status}`) + return downloadResponse?.[0]?.status === "completed" && downloadResponse?.[0]?.fileStoreid; +} + +const conditionForTermination2 = (downloadResponse: any) => { + logger.info(`current status ${downloadResponse?.[0]?.status}`) + return downloadResponse?.[0]?.status === "completed" && downloadResponse?.[0]?.processedFilestoreId; +} + +export const createAndPollForCompletion = async (request: any) => { + try { + // Step 1: Create data + logger.info("Creating data..."); + const resourceDetails = await createDataService(request); + const resourceId = resourceDetails?.id; + + if (!resourceId) { + throwError("DATA", 500, "DATA_CREATE_ERROR", `Failed to retrieve resource ID from creation response for type ${request?.body?.ResourceDetails?.type}`); + } + + logger.info(`Created resource with ID: ${resourceId} of type ${request?.body?.ResourceDetails?.type}`); + + // Step 2: Poll for completion + const polledResponse = await pollForTemplateGeneration( + () => searchData(resourceId, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.type), + conditionForTermination2, + 3000, + 30 + ); + + logger.info("Polling completed successfully", polledResponse); + return polledResponse; + } catch (error: any) { + logger.error("Error during creation or polling", error); + throw error; + } +}; + + + +async function searchData(resourceId: any, tenantId: any, type: any) { + const SearchCriteria = { + id: [resourceId], + tenantId: tenantId, + type: type + }; + const searchBody = { ...defaultRequestInfo, SearchCriteria } + const request: any = { + body: { ...searchBody } + } + + const searchResponse: any = await searchDataService(request); + return searchResponse; +} + + + +export const getTheGeneratedResource = async ( + campaignId: string, + tenantId: string, + type: string, + hierarchy: string +) => { + try { + // Await the response from polling for template generation + const polledResponse: any = await pollForTemplateGeneration( + () => downloadTemplate(campaignId, tenantId, type, hierarchy), + conditionForTermination + ); + + // Log the polled response for debugging + logger.debug(polledResponse); + logger.debug(`polledResponse : ${getFormattedStringForDebug(polledResponse)}`); + + // Return the fileStoreid from the response, ensuring the correct format + return polledResponse?.[0]?.fileStoreid; + + } catch (error: any) { + // Log any error that occurs during polling or processing + logger.error(`Error while fetching the generated resource: ${error?.message}`); + } +} diff --git a/health-services/project-factory/src/server/utils/redisUtils.ts b/health-services/project-factory/src/server/utils/redisUtils.ts index f62177928d9..320705df1d6 100644 --- a/health-services/project-factory/src/server/utils/redisUtils.ts +++ b/health-services/project-factory/src/server/utils/redisUtils.ts @@ -1,5 +1,6 @@ import Redis from "ioredis"; import config from "../config"; +import { logger } from "./logger"; const redis = new Redis({ host: config.host.redisHost, @@ -18,12 +19,59 @@ const redis = new Redis({ async function checkRedisConnection(): Promise { try { - await redis.ping(); + if (config?.cacheValues?.cacheEnabled) { + await redis.ping(); + } return true; + } catch (error) { console.error("Redis connection error:", error); return false; } } -export { redis, checkRedisConnection }; +// Listen for the 'connect' event +redis.on('connect', () => { + logger.info(`Successfully connected to Redis! host :: ${config.host.redisHost} & port :: ${config.cacheValues.redisPort}`); + // You can add additional code here to perform actions after a successful connection +}); + +// Listen for errors +redis.on('error', (err) => { + logger.info(`failed connecting to Redis! host :: ${config.host.redisHost} & port :: ${config.cacheValues.redisPort}`); + logger.error("Redis connection error:", err); +}); + + + +async function deleteRedisCacheKeysWithPrefix(prefix: any) { + try { + // Use SCAN instead of KEYS to avoid performance issues + let cursor = '0'; + let keysToDelete: any = []; + + do { + const result = await redis.scan(cursor, 'MATCH', `${prefix}*`, 'COUNT', '100'); + cursor = result[0]; + const keys = result[1]; + + if (keys.length > 0) { + keysToDelete = keysToDelete.concat(keys); + logger.info("Cache keys found to be deleted: " + keys); + } + } while (cursor !== '0'); + + if (keysToDelete.length > 0) { + await redis.del(...keysToDelete); + logger.info(`Deleted keys with prefix "${prefix}":`, keysToDelete); + } else { + logger.info(`No keys found with prefix "${prefix}"`); + } + } catch (error) { + logger.info("Error deleting keys:", error); + throw error; + } +} + + +export { redis, checkRedisConnection, deleteRedisCacheKeysWithPrefix }; diff --git a/health-services/project-factory/src/server/utils/request.ts b/health-services/project-factory/src/server/utils/request.ts index ef23426cc0e..9cc340605ff 100644 --- a/health-services/project-factory/src/server/utils/request.ts +++ b/health-services/project-factory/src/server/utils/request.ts @@ -47,6 +47,7 @@ const cacheEnabled = config.cacheValues.cacheEnabled; // Variable to indicate wh /** * Used to Make API call through axios library + * @author jagankumar-egov * * @param {string} _url - The URL to make the HTTP request to * @param {Object} _requestBody - The request body @@ -148,25 +149,50 @@ const httpRequest = async ( errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] } )}` ); - if (retry) { + if ( + retry || + (config.values.autoRetryIfHttpError && + config.values.autoRetryIfHttpError?.includes( + errorResponse?.data?.Errors?.[0]?.code + )) + ) { + logger.info( + `retrying the failed api call since retry is enabled or error is equal to configured ${config.values.autoRetryIfHttpError}` + ); attempt++; if (attempt >= maxAttempts) { if (dontThrowError) { - logger.warn(`Maximum retry attempts reached for httprequest with url ${_url}`); - return errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] }; + logger.warn( + `Maximum retry attempts reached for httprequest with url ${_url}` + ); + return ( + errorResponse?.data || { + Errors: [{ code: error.message, description: error.stack }], + } + ); } else { throwTheHttpError(errorResponse, error, _url); } } - logger.warn(`Waiting for 20 seconds before retrying httprequest with url ${_url}`); + logger.warn( + `Waiting for 20 seconds before retrying httprequest with url ${_url}` + ); await new Promise((resolve) => setTimeout(resolve, 20000)); } else if (dontThrowError) { logger.warn( - `Error occurred while making request to ${getServiceName(_url)}: returning error response ${JSON.stringify( - errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] } + `Error occurred while making request to ${getServiceName( + _url + )}: returning error response ${JSON.stringify( + errorResponse?.data || { + Errors: [{ code: error.message, description: error.stack }], + } )}` ); - return errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] }; + return ( + errorResponse?.data || { + Errors: [{ code: error.message, description: error.stack }], + } + ); } else { throwTheHttpError(errorResponse, error, _url); } diff --git a/health-services/project-factory/src/server/utils/targetUtils.ts b/health-services/project-factory/src/server/utils/targetUtils.ts index 74a91782dba..7e102feb6d8 100644 --- a/health-services/project-factory/src/server/utils/targetUtils.ts +++ b/health-services/project-factory/src/server/utils/targetUtils.ts @@ -99,7 +99,7 @@ async function updateTargetColumnsIfDeliveryConditionsDifferForSMC(request: any) const newRequestBody = { RequestInfo: request?.body?.RequestInfo, Filters: { - boundaries: request?.body?.CampaignDetails?.boundaries + boundaries: request?.body?.boundariesCombined } }; diff --git a/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts index a2528ce515d..ed8047f9fd7 100644 --- a/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts +++ b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts @@ -11,36 +11,108 @@ import { logger } from "../logger"; * @param hierarchyType - Type of hierarchy for the localisation module. * @param request - Request object containing necessary information. */ -export const transformAndCreateLocalisation = ( + +export const transformAndCreateLocalisation = async ( boundaryMap: any, request: any ) => { - const { tenantId, hierarchyType } = request?.body?.ResourceDetails || {}; + const CHUNK_SIZE = 200; // Adjust this size based on your API limits and performance + + try { + const { tenantId, hierarchyType } = request?.body?.ResourceDetails || {}; - // Get localisation module name based on hierarchy type - const module = getLocalisationModuleName(hierarchyType); + // Get localisation module name based on hierarchy type + const module = getLocalisationModuleName(hierarchyType); - // Get locale from request object - const locale = getLocaleFromRequest(request); + // Get locale from request object + const locale = getLocaleFromRequest(request); - // Array to store localisation messages - const localisationMessages: any = []; + // Array to store localisation messages + const localisationMessages: any[] = []; - // Iterate over boundary map to transform into localisation messagess - boundaryMap.forEach((code: string, boundary: any) => { // Add transformed message to localisation messages array - localisationMessages.push({ - code, - message: boundary.value, - module, - locale, + // Iterate over boundary map to transform into localisation messages + boundaryMap.forEach((code: string, boundary: any) => { + if(boundary.value !== '' && boundary.value !== undefined){ + localisationMessages.push({ + code, + message: boundary.value, + module, + locale, + }); + } }); - }) + logger.info("Localisation message transformed successfully from the boundary map"); + + // Call the chunk upload function + await uploadInChunks(localisationMessages, CHUNK_SIZE, tenantId, request); + + logger.info("All chunks uploaded successfully"); + + } catch (error) { + logger.error("Error during transformation and localisation creation:", error); + throw error; // You can further handle this error (e.g., send failure response to client) + } +} + +const uploadInChunks = async (messages: any, chunkSize: any, tenantId: any, request: any) => { + // Check if messages is a valid array and chunkSize is a positive number + if (!Array.isArray(messages) || messages.length === 0) { + logger.error("Invalid or empty messages array provided"); + return; + } + if (typeof chunkSize !== 'number' || chunkSize <= 0) { + logger.error("Invalid chunkSize provided"); + return; + } + const MAX_RETRIES = 3; // Maximum number of retries for a chunk + // Break the messages array into chunks + for (let i = 0; i < messages.length; i += chunkSize) { + let retries = 0; + let success = false; + const chunk = messages.slice(i, i + chunkSize); + logger.info(`Total messages count ${messages?.length}`); + while (retries <= MAX_RETRIES) { + try { + logger.info(`Uploading chunk ${Math.floor(i / chunkSize) + 1}/${Math.ceil(messages.length / chunkSize)} of size ${chunkSize}`); + + // Check if tenantId and request are defined + if (!tenantId || !request) { + throw new Error("tenantId or request is not defined"); + } + + // Instantiate localisation controller + const localisation = Localisation.getInstance(); + + // Upload the current chunk + await localisation.createLocalisation(chunk, tenantId, request); + + logger.info(`Successfully uploaded chunk ${Math.floor(i / chunkSize) + 1}`); + success = true; // Mark as successful + break; + } catch (error: any) { + retries += 1; + logger.info(`Retrying chunk ${Math.floor(i / chunkSize) + 1}, Attempt ${retries}`); + logger.error( + `Error uploading chunk ${Math.floor(i / chunkSize) + 1}, Attempt ${retries}: ${error.message}` + ); + + // If retries are exhausted, log failure and move on + if (retries > MAX_RETRIES) { + logger.error( + `Failed to upload chunk ${Math.floor(i / chunkSize) + 1} after ${MAX_RETRIES} retries` + ); + } + + // Optional: Add a delay between retries + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + } + if (!success) { + logger.warn(`Skipping chunk ${Math.floor(i / chunkSize) + 1} after exhausting retries`); + } + } + logger.info("Finished processing all chunks"); +}; - logger.info("localisation message transformed successfully from the boundary map") - // Instantiate localisation controller - const localisation = Localisation.getInstance(); - // Call method to create localisation entries - localisation.createLocalisation(localisationMessages, tenantId,request); - }; diff --git a/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts b/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts index e279306f7ce..c8cddff7a18 100644 --- a/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts +++ b/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts @@ -54,32 +54,40 @@ const defaultProjectType: any = { Convert campaign details to project details enriched with campaign information. */ export const projectTypeConversion = ( - projectType: any = {}, campaignObject: any = {} ) => { const deliveryRules = campaignObject.deliveryRules; - const resources = getUniqueArrayByProductVariantId(deliveryRules.flatMap((e: { products: any }) => - [...e.products].map((ele, ind) => ({ - isBaseUnitVariant: ind == 0, - productVariantId: ele.value, - })) - )); - const minAndMaxAge = getMinAndMaxAge(deliveryRules); - var newProjectType = { - ...projectType, - validMinAge: minAndMaxAge?.min, - validMaxAge: minAndMaxAge?.max, - name: campaignObject.campaignName, - resources, - }; - /*Handled the logics for the SMC Project Type */ - if (projectType.code == "MR-DN") { - newProjectType["cycles"] = transformData(deliveryRules); - } - logger.debug( - "transformed projectType : " + getFormattedStringForDebug(newProjectType) - ); - return newProjectType; + // const resources = getUniqueArrayByProductVariantId(deliveryRules.flatMap((e: { products: any }) => + // [...e.products].map((ele, ind) => ({ + // isBaseUnitVariant: ind == 0, + // productVariantId: ele.value, + // })) + // )); +// /* Temporay fix for project creation of LLIN since the structure of delivery rules is getting changed */ +// const resources = getUniqueArrayByProductVariantId(deliveryRules.flatMap((e:any) => +// [...e.deliveries].map((ele, ind) => ({ +// isBaseUnitVariant: ind == 0, +// productVariantId: ele.deliveryRules?.[0]?.products?.[0]?.value, +// })) +// )); +// const minAndMaxAge = getMinAndMaxAge(deliveryRules); +// var newProjectType = { +// ...projectType, +// validMinAge: minAndMaxAge?.min, +// validMaxAge: minAndMaxAge?.max, +// name: campaignObject.campaignName, +// resources, +// }; +// /*Handled the logics for the SMC Project Type */ +// if (projectType.code == "MR-DN") { +// newProjectType["cycles"] = transformData(deliveryRules); +// } +// logger.debug( +// "transformed projectType : " + getFormattedStringForDebug(newProjectType) +// ); + /* since the structure of delivery rules is getting changed so returning back the same delivery rules */ + + return deliveryRules?.[0] || defaultProjectType?.["LLIN-mz"]; }; /* Enrich project details from campaign details. @@ -94,10 +102,7 @@ export const enrichProjectDetailsFromCampaignDetails = ( logger.debug( "project type : " + getFormattedStringForDebug(projectTypeObject) ); - const defaultProject = - projectTypeObject || - defaultProjectType?.[projectType] || - defaultProjectType?.["MR-DN"]; + const defaultProject = projectTypeConversion( CampaignDetails); return [ { tenantId, @@ -106,11 +111,11 @@ export const enrichProjectDetailsFromCampaignDetails = ( endDate, projectSubType: projectType, department: defaultProject?.group, - description: defaultProject?.name, + description:`${defaultProject?.name}, disease ${defaultProject?.group} campaign created through Admin Console with Campaign Id as ${CampaignDetails?.campaignNumber}`, projectTypeId: defaultProject?.id, name: campaignName, additionalDetails: { - projectType: projectTypeConversion(defaultProject, CampaignDetails), + projectType: defaultProject, }, }, ]; @@ -118,7 +123,7 @@ export const enrichProjectDetailsFromCampaignDetails = ( /* construct max and min age */ -const getMinAndMaxAge = (deliveries = []) => { +export const getMinAndMaxAge = (deliveries = []) => { // Flatten the conditions arrays from all delivery objects and filter to keep only 'Age' attributes const ageConditions = deliveries .flatMap((e: any) => e?.conditions) @@ -281,7 +286,7 @@ const getRequiredCondition = (conditions: Condition[]): string => { }; // Transformation function -const transformData = (input: DeliveryItem[]): TransformedCycle[] => { +export const transformData = (input: DeliveryItem[]): TransformedCycle[] => { const groupedByCycle = input.reduce>((acc, item) => { const { cycleNumber, deliveryNumber, deliveryType, products, conditions,startDate,endDate } = item; diff --git a/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts b/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts index 783fb22edd8..7e5391847fb 100644 --- a/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts +++ b/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts @@ -39,6 +39,8 @@ export const campaignDetailsTransformer = (dbRows: any[] = []) => { status: row?.status, action: row?.action, campaignNumber: row?.campaignnumber, + isActive: row?.isactive, + parentId: row?.parentid, campaignName: row?.campaignname, projectType: row?.projecttype, hierarchyType: row?.hierarchytype, diff --git a/health-services/project-factory/src/server/validators/campaignValidators.ts b/health-services/project-factory/src/server/validators/campaignValidators.ts index 1af1e291eba..cfbc1e16997 100644 --- a/health-services/project-factory/src/server/validators/campaignValidators.ts +++ b/health-services/project-factory/src/server/validators/campaignValidators.ts @@ -6,7 +6,7 @@ import { getCampaignSearchResponse, getHeadersOfBoundarySheet, getHierarchy, han import { campaignDetailsSchema } from "../config/models/campaignDetails"; import Ajv from "ajv"; import { getDifferentDistrictTabs, getLocalizedHeaders, getLocalizedMessagesHandler, getMdmsDataBasedOnCampaignType, replicateRequest, throwError } from "../utils/genericUtils"; -import { createBoundaryMap, generateProcessedFileAndPersist, getFinalValidHeadersForTargetSheetAsPerCampaignType, getLocalizedName } from "../utils/campaignUtils"; +import { createBoundaryMap, enrichInnerCampaignDetails, generateProcessedFileAndPersist, getFinalValidHeadersForTargetSheetAsPerCampaignType, getLocalizedName } from "../utils/campaignUtils"; import { validateBodyViaSchema, validateCampaignBodyViaSchema, validateHierarchyType } from "./genericValidator"; import { searchCriteriaSchema } from "../config/models/SearchCriteria"; import { searchCampaignDetailsSchema } from "../config/models/searchCampaignDetails"; @@ -21,7 +21,12 @@ import { campaignStatuses, resourceDataStatuses } from "../config/constants"; import { getBoundaryColumnName, getBoundaryTabName } from "../utils/boundaryUtils"; import addAjvErrors from "ajv-errors"; import { generateTargetColumnsBasedOnDeliveryConditions, isDynamicTargetTemplateForProjectType, modifyDeliveryConditions } from "../utils/targetUtils"; - +import { getBoundariesFromCampaignSearchResponse, validateBoundariesIfParentPresent } from "../utils/onGoingCampaignUpdateUtils"; +import { validateFacilityBoundaryForLowestLevel, validateLatLongForMicroplanCampaigns, validatePhoneNumberSheetWise, validateTargetsForMicroplanCampaigns, validateUniqueSheetWise, validateUserForMicroplan } from "./microplanValidators"; +import { produceModifiedMessages } from "../kafka/Producer"; +import { planConfigSearch, planFacilitySearch } from "../utils/microplanUtils"; +import { getPvarIds } from "../utils/campaignMappingUtils"; +import { fetchProductVariants } from "../api/healthApis"; @@ -83,158 +88,9 @@ async function fetchBoundariesFromCampaignDetails(request: any) { return responseBoundaries; } -// // Compares unique boundaries with response boundaries and throws error for missing codes. -// function compareBoundariesWithUnique(uniqueBoundaries: any[], responseBoundaries: any[], request: any) { -// // Extracts boundary codes from response boundaries -// const responseBoundaryCodes = responseBoundaries.map(boundary => boundary.code.trim()); - -// // Finds missing codes from unique boundaries -// const missingCodes = uniqueBoundaries.filter(code => !responseBoundaryCodes.includes(code)); - -// // Throws error if missing codes exist -// if (missingCodes.length > 0) { -// throwError( -// "COMMON", -// 400, -// "VALIDATION_ERROR", -// `Boundary codes ${missingCodes.join(', ')} do not exist in hierarchyType ${request?.body?.ResourceDetails?.hierarchyType}` -// ); -// } -// } - -// Validates unique boundaries against the response boundaries. -// async function validateUniqueBoundaries(uniqueBoundaries: any[], request: any) { -// // Fetches response boundaries in chunks -// const responseBoundaries = await fetchBoundariesInChunks(request); - -// // Compares unique boundaries with response boundaries -// compareBoundariesWithUnique(uniqueBoundaries, responseBoundaries, request); -// } - - - - -// async function validateBoundaryData(data: any[], request: any, boundaryColumn: any, localizationMap: any) { -// const boundarySet = new Set(); // Create a Set to store unique boundaries -// logger.info("validating for the boundary data") -// const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; -// const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap) : null; -// if (activeColumnName && uniqueIdentifierColumnName) { -// data = data.filter((item: any) => item[activeColumnName] === "Active" || !item[uniqueIdentifierColumnName]); -// data.forEach((item: any) => item[activeColumnName] = "Active"); -// } -// if (data.length == 0) { -// if (request?.body?.ResourceDetails?.type == "facility") { -// throwError("COMMON", 400, "VALIDATION_ERROR", "All facilities are set to Inactive for this campaign. Please set at least one facility to Active for this campaign or add a new facility for this campaign"); -// } -// else { -// throwError("COMMON", 400, "VALIDATION_ERROR", "Data is empty for this campaign, add atleast one data row"); -// } -// } -// data.forEach((element) => { -// const boundaries = element[boundaryColumn]; -// if (!boundaries) { -// throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Code is required for element in rowNumber ${element['!row#number!']}`); -// } - -// const boundaryList = boundaries.split(",").map((boundary: any) => boundary.trim()); -// if (boundaryList.length === 0) { -// throwError("COMMON", 400, "VALIDATION_ERROR", `At least 1 boundary is required for element in rowNumber ${element['!row#number!']}`); -// } - -// for (const boundary of boundaryList) { -// if (!boundary) { -// throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary format is invalid in rowNumber ${element['!row#number!']}. Put it with one comma between boundary codes`); -// } -// boundarySet.add(boundary); // Add boundary to the set -// } -// }); -// const uniqueBoundaries = Array.from(boundarySet); -// await validateUniqueBoundaries(uniqueBoundaries, request); -// } - -// async function validateTargetBoundaryData(data: any[], request: any, boundaryColumn: any, errors: any[], localizationMap?: any) { -// // const responseBoundaries = await fetchBoundariesInChunks(request); -// const responseBoundaries = await getTargetBoundariesRelatedToCampaignId(request, localizationMap); -// const responseBoundaryCodes = responseBoundaries.map((boundary: any) => boundary.code); -// // Iterate through each array of objects -// for (const key in data) { -// const isNotBoundaryOrReadMeTab = key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap); -// if (isNotBoundaryOrReadMeTab) { -// if (Array.isArray(data[key])) { -// const boundaryData = data[key]; -// const boundarySet = new Set(); // Create a Set to store unique boundaries for given sheet -// boundaryData.forEach((element: any, index: number) => { -// const boundaries = element?.[boundaryColumn]; // Access "Boundary Code" property directly -// if (!boundaries) { -// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Boundary Code is required for element at row ${element["!row#number!"]} for sheet ${key}`, sheetName: key }) -// } else { -// if (typeof boundaries !== 'string') { -// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Boundary Code is not of type string at row ${element["!row#number!"]} in boundary sheet ${key}`, sheetName: key }); -// } else { -// const boundaryList = boundaries.split(",").map((boundary: any) => boundary.trim()); -// if (boundaryList.length === 0 || boundaryList.includes('')) { -// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `No boundary code found for row ${element["!row#number!"]} in boundary sheet ${key}`, sheetName: key }) -// } -// if (boundaryList.length > 1) { -// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `More than one Boundary Code found at row ${element["!row#number!"]} of sheet ${key}`, sheetName: key }) -// } -// if (boundaryList.length === 1) { -// const boundaryCode = boundaryList[0]; -// if (boundarySet.has(boundaryCode)) { -// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Duplicacy of boundary Code at row ${element["!row#number!"]} of sheet ${key}`, sheetName: key }) -// } -// if (!responseBoundaryCodes.includes(boundaryCode)) { -// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Boundary Code at row ${element["!row#number!"]} of sheet ${key} is not present in the selected boundaries`, sheetName: key }) -// } -// boundarySet.add(boundaryCode); -// } -// } -// } -// }); -// } -// } -// } -// } - - - -// async function validateTargetsAtLowestLevelPresentOrNot(data: any[], request: any, errors: any[], localizationMap?: any) { -// const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); -// const modifiedHierarchy = hierarchy.map(ele => `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase()) -// const localizedHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); -// const dataToBeValidated = modifyTargetData(data); -// let maxKeyIndex = -1; -// dataToBeValidated.forEach(obj => { -// const keyIndex = calculateKeyIndex(obj, localizedHierarchy, localizationMap); -// if (keyIndex > maxKeyIndex) { -// maxKeyIndex = keyIndex; -// } -// }) -// const lowestLevelHierarchy = localizedHierarchy[maxKeyIndex]; -// await validateTargets(request, data, lowestLevelHierarchy, errors, localizationMap); -// } - - -async function validateTargets(request: any, data: any[], errors: any[], localizationMap?: any) { - let columnsToValidate: any; - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0) { - - const modifiedUniqueDeliveryConditions = modifyDeliveryConditions(campaignObject.deliveryRules); - columnsToValidate = generateTargetColumnsBasedOnDeliveryConditions(modifiedUniqueDeliveryConditions, localizationMap); - - } - else { - const mdmsResponse = await getMdmsDataBasedOnCampaignType(request); - const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; - const requiredColumns = mdmsResponse?.required; - columnsToValidate = columnsNotToBeFreezed.filter((element: any) => requiredColumns.includes(element)); - } - const localizedTargetColumnNames = getLocalizedHeaders(columnsToValidate, localizationMap); +function validateTargetForNormalCampaigns(data: any, errors: any, localizedTargetColumnNames: any, localizationMap?: { [key: string]: string }) { for (const key in data) { - if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { + if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config.values?.readMeTab, localizationMap)) { if (Array.isArray(data[key])) { const boundaryData = data[key]; boundaryData.forEach((obj: any, index: number) => { @@ -276,8 +132,34 @@ async function validateTargets(request: any, data: any[], errors: any[], localiz } } -async function validateUnique(schema: any, data: any[], request: any) { - const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + +async function validateTargets(request: any, data: any[], errors: any[], localizationMap?: any) { + let columnsToValidate: any; + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0) { + + const modifiedUniqueDeliveryConditions = modifyDeliveryConditions(campaignObject.deliveryRules); + columnsToValidate = generateTargetColumnsBasedOnDeliveryConditions(modifiedUniqueDeliveryConditions, localizationMap); + + } + else { + const mdmsResponse = await getMdmsDataBasedOnCampaignType(request); + const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + const requiredColumns = mdmsResponse?.required; + columnsToValidate = columnsNotToBeFreezed.filter((element: any) => requiredColumns.includes(element)); + } + const localizedTargetColumnNames = getLocalizedHeaders(columnsToValidate, localizationMap); + if (request?.body?.ResourceDetails?.additionalDetails?.source === "microplan") { + validateTargetsForMicroplanCampaigns(data, errors, localizedTargetColumnNames, localizationMap); + validateLatLongForMicroplanCampaigns(data, errors, localizationMap); + } + else { + validateTargetForNormalCampaigns(data, errors, localizedTargetColumnNames, localizationMap); + } +} + +function validateUnique(schema: any, data: any[], request: any, localizationMap: any) { if (schema?.unique) { const uniqueElements = schema.unique; const errors = []; @@ -288,7 +170,7 @@ async function validateUnique(schema: any, data: any[], request: any) { // Iterate over each data object and check uniqueness for (const item of data) { const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName; - const localizedUniqueIdentifierColumnName = await getLocalizedName(uniqueIdentifierColumnName, localizationMap); + const localizedUniqueIdentifierColumnName = getLocalizedName(uniqueIdentifierColumnName, localizationMap); const value = item[element]; const rowNum = item['!row#number!']; if (!localizedUniqueIdentifierColumnName || !item[localizedUniqueIdentifierColumnName]) { @@ -343,6 +225,7 @@ function validatePhoneNumber(datas: any[], localizationMap: any) { } } + async function changeSchemaErrorMessage(schema: any, localizationMap?: any) { if (schema?.errorMessage) { for (const key in schema.errorMessage) { @@ -354,9 +237,54 @@ async function changeSchemaErrorMessage(schema: any, localizationMap?: any) { return schema; // Return unmodified schema if no error message } +function validateData(data: any[], validationErrors: any[], activeColumnName: any, uniqueIdentifierColumnName: any, validate: any) { + data.forEach((item: any) => { + if (activeColumnName) { + if (!item?.[activeColumnName]) { + validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should not be empty` }] }); + } + else if (item?.[activeColumnName] != "Active" && item?.[activeColumnName] != "Inactive") { + validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should be equal to one of the allowed values. Allowed values are Active, Inactive` }] }); + } + } + const active = activeColumnName ? item[activeColumnName] : "Active"; + if (active == "Active" || !item?.[uniqueIdentifierColumnName]) { + const validationResult = validate(item); + if (!validationResult) { + validationErrors.push({ index: item?.["!row#number!"], errors: validate.errors }); + } + } + }); +} + +function enrichRowMappingViaValidation(validationErrors: any[], rowMapping: any, localizationMap?: any) { + if (validationErrors.length > 0) { + const errorMessage = validationErrors.map(({ index, message, errors }) => { + const formattedErrors = errors ? errors.map((error: any) => { + let instancePath = error.instancePath || ''; // Assign an empty string if dataPath is not available + if (instancePath.startsWith('/')) { + instancePath = instancePath.slice(1); + } + if (error.keyword === 'required') { + const missingProperty = error.params?.missingProperty || ''; + return `Data at row ${index} in column '${missingProperty}' should not be empty`; + } + let formattedError = `in column '${instancePath}' ${getLocalizedName(error.message, localizationMap)}`; + if (error.keyword === 'enum' && error.params && error.params.allowedValues) { + formattedError += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; + } + return `Data at row ${index} ${formattedError}` + }).join(' ; ') : message; + return formattedErrors; + }).join(' ; '); + throwError("COMMON", 400, "VALIDATION_ERROR", errorMessage); + } else { + logger.info("All Data rows are valid."); + } +} -async function validateViaSchema(data: any, schema: any, request: any, localizationMap?: any) { +export async function validateViaSchema(data: any, schema: any, request: any, localizationMap?: any) { if (schema) { const newSchema: any = await changeSchemaErrorMessage(schema, localizationMap) const ajv = new Ajv({ allErrors: true, strict: false }); // enable allErrors to get all validation errors @@ -368,54 +296,112 @@ async function validateViaSchema(data: any, schema: any, request: any, localizat if (request?.body?.ResourceDetails?.type == "user") { validatePhoneNumber(data, localizationMap); } - if (data?.length > 0) { - data.forEach((item: any) => { - if (activeColumnName) { - if (!item?.[activeColumnName]) { - validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should not be empty` }] }); - } - else if (item?.[activeColumnName] != "Active" && item?.[activeColumnName] != "Inactive") { - validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should be equal to one of the allowed values. Allowed values are Active, Inactive` }] }); - } - } - const active = activeColumnName ? item[activeColumnName] : "Active"; - if (active == "Active" || !item?.[uniqueIdentifierColumnName]) { - const validationResult = validate(item); - if (!validationResult) { - validationErrors.push({ index: item?.["!row#number!"], errors: validate.errors }); + if (data?.length > 0 && request?.body?.ResourceDetails?.additionalDetails?.source != "microplan") { + if (!request?.body?.parentCampaignObject && data[0]?.[getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", localizationMap)]) { + throwError("COMMON", 400, "VALIDATION_ERROR", `${request?.body?.ResourceDetails?.type} template downloaded from update campaign flow has been uploaded in create campaign flow`); + } + validateData(data, validationErrors, activeColumnName, uniqueIdentifierColumnName, validate); + validateUnique(newSchema, data, request, localizationMap); + enrichRowMappingViaValidation(validationErrors, request?.body?.rowMapping, localizationMap); + } + if (data?.length == 0) { + throwError("FILE", 400, "INVALID_FILE_ERROR", "Data rows cannot be empty"); + } + } else { + logger.info("Skipping schema validation"); + } +} + +function validateDataSheetWise(data: any, validate: any, validationErrors: any[], uniqueIdentifierColumnName: any, activeColumnName: any) { + data.forEach((item: any) => { + const validationResult = validate(item); + if (!validationResult) { + validationErrors.push({ index: item?.["!row#number!"], errors: validate.errors }); + } + }); +} + +function enrichRowMappingViaValidationSheetwise(rowMapping: any, validationErrors: any[], localizationMap: any) { + if (validationErrors.length > 0) { + validationErrors.map(({ index, message, errors }) => { + if (errors) { + errors.map((error: any) => { + let instancePath = error.instancePath || ''; // Assign an empty string if instancePath is not available + if (instancePath.startsWith('/')) { + instancePath = instancePath.slice(1); } - } - }); - await validateUnique(newSchema, data, request); - if (validationErrors.length > 0) { - const errorMessage = validationErrors.map(({ index, message, errors }) => { - const formattedErrors = errors ? errors.map((error: any) => { - let instancePath = error.instancePath || ''; // Assign an empty string if dataPath is not available - if (instancePath.startsWith('/')) { - instancePath = instancePath.slice(1); - } - if (error.keyword === 'required') { - const missingProperty = error.params?.missingProperty || ''; - return `Data at row ${index} in column '${missingProperty}' should not be empty`; + + // Handle 'required' keyword errors + if (error.keyword === 'required') { + const missingProperty = error.params?.missingProperty || ''; + if (!rowMapping[index]) { + rowMapping[index] = []; } - let formattedError = `in column '${instancePath}' ${getLocalizedName(error.message, localizationMap)}`; + rowMapping[index].push(`Data in column '${missingProperty}' should not be empty`); + } + else { + // Format the general error message + let formattedError = `Data in column '${instancePath}' ${getLocalizedName(error.message, localizationMap)}`; + + // Handle 'enum' keyword errors if (error.keyword === 'enum' && error.params && error.params.allowedValues) { formattedError += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; } - return `Data at row ${index} ${formattedError}` - }).join(' ; ') : message; - return formattedErrors; - }).join(' ; '); - throwError("COMMON", 400, "VALIDATION_ERROR", errorMessage); - } else { - logger.info("All Data rows are valid."); + else if (error.keyword === 'pattern') { + formattedError = `Data in column '${instancePath}' is invalid` + } + + // Ensure rowMapping[index] exists + if (!rowMapping[index]) { + rowMapping[index] = []; + } + rowMapping[index].push(`${formattedError}`); + } + }) + } + }); + } + else { + logger.info("All Data rows are valid."); + } +} + +export async function validateViaSchemaSheetWise(dataFromExcel: any, schema: any, request: any, localizationMap?: any) { + const errorMap: any = {}; + for (const sheetName of Object.keys(dataFromExcel)) { + const data = dataFromExcel[sheetName]; + const rowMapping: any = {}; + if (schema) { + const newSchema: any = await changeSchemaErrorMessage(schema, localizationMap) + const ajv = new Ajv({ allErrors: true, strict: false }); // enable allErrors to get all validation errors + addAjvErrors(ajv); + const validate = ajv.compile(newSchema); + const validationErrors: any[] = []; + const uniqueIdentifierColumnName = getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap); + const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; + if (request?.body?.ResourceDetails?.type == "user" && request?.body?.ResourceDetails?.additionalDetails?.source == "microplan") { + validateUserForMicroplan(data, sheetName, request, errorMap, newSchema, rowMapping, localizationMap); + } + else { + if (request?.body?.ResourceDetails?.type == "user") { + validatePhoneNumberSheetWise(data, localizationMap, rowMapping); + } + if (data?.length > 0) { + validateDataSheetWise(data, validate, validationErrors, uniqueIdentifierColumnName, activeColumnName); + validateUniqueSheetWise(newSchema, data, request, rowMapping, localizationMap); + enrichRowMappingViaValidationSheetwise(rowMapping, validationErrors, localizationMap); + } else { + errorMap[sheetName] = { 2: ["Data rows cannot be empty"] }; + } } } else { - throwError("FILE", 400, "INVALID_FILE_ERROR", "Data rows cannot be empty"); + logger.info("Skipping schema validation"); + } + if (Object.keys(rowMapping).length > 0) { + errorMap[sheetName] = rowMapping; } - } else { - logger.info("Skipping schema validation"); } + return errorMap; } @@ -495,7 +481,7 @@ function validateStorageCapacity(obj: any, index: any) { async function validateCampaignId(request: any) { - const { campaignId, tenantId, type } = request?.body?.ResourceDetails; + const { campaignId, tenantId, type, additionalDetails } = request?.body?.ResourceDetails; if (type == "boundary") { return; } @@ -503,28 +489,30 @@ async function validateCampaignId(request: any) { throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignId is missing"); } else { - const searchBody = { - CampaignDetails: { + // const searchBody = { + const CampaignDetails= { ids: [campaignId], tenantId: tenantId } - } - const req: any = replicateRequest(request, searchBody); - const response = await searchProjectTypeCampaignService(req); + // const req: any = replicateRequest(request, searchBody); + const response = await searchProjectTypeCampaignService(CampaignDetails); if (response?.CampaignDetails?.[0]) { - const campaign = response?.CampaignDetails?.[0] - if (!campaign?.boundaries) { + const boundaries = await getBoundariesFromCampaignSearchResponse(request, response?.CampaignDetails?.[0]); + if (!boundaries) { throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign with given campaignId does not have any boundaries"); } - if (!Array.isArray(campaign?.boundaries)) { + if (!Array.isArray(boundaries)) { throwError("COMMON", 400, "VALIDATION_ERROR", "Boundaries of campaign with given campaignId is not an array"); } - if (campaign?.boundaries?.length === 0) { + if (boundaries?.length === 0) { throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign with given campaignId does not have any boundaries"); } + request.body.campaignBoundaries = boundaries } else { - throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while validating campaignId"); + if (!(additionalDetails?.source == "microplan" && type == "user")) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while validating campaignId"); + } } } } @@ -535,9 +523,12 @@ async function validateCreateRequest(request: any, localizationMap?: any) { throwError("COMMON", 400, "VALIDATION_ERROR", "ResourceDetails is missing or empty or null"); } else { + const type = request?.body?.ResourceDetails?.type; // validate create request body validateBodyViaSchema(createRequestSchema, request.body.ResourceDetails); - await validateCampaignId(request); + if (type !== "boundaryManagement" && request?.body?.ResourceDetails.campaignId !== "default") { + await validateCampaignId(request); + } await validateHierarchyType(request, request?.body?.ResourceDetails?.hierarchyType, request?.body?.ResourceDetails?.tenantId); if (request?.body?.ResourceDetails?.tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is not matching with userInfo"); @@ -547,13 +538,6 @@ async function validateCreateRequest(request: any, localizationMap?: any) { if (request.body.ResourceDetails.type == 'boundary') { await validateBoundarySheetData(request, fileUrl, localizationMap); } - // if (request?.body?.ResourceDetails?.type == 'boundaryWithTarget') { - // const targetWorkbook: any = await getTargetWorkbook(fileUrl); - // const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); - // const finalValidHeadersForTargetSheetAsPerCampaignType = await getFinalValidHeadersForTargetSheetAsPerCampaignType(request, hierarchy, localizationMap); - // logger.info("finalValidHeadersForTargetSheetAsPerCampaignType :" + JSON.stringify(finalValidHeadersForTargetSheetAsPerCampaignType)); - // validateTabsWithTargetInTargetSheet(targetWorkbook, finalValidHeadersForTargetSheetAsPerCampaignType); - // } } } @@ -561,9 +545,10 @@ function validateHeadersOfTabsWithTargetInTargetSheet(targetWorkbook: any, expec targetWorkbook.eachSheet((worksheet: any, sheetId: any) => { if (sheetId > 2) { // Starting from the second sheet // Convert the sheet to an array of headers - const headersToValidate = worksheet.getRow(1).values + let headersToValidate = worksheet.getRow(1).values .filter((header: any) => header !== undefined && header !== null && header.toString().trim() !== '') .map((header: any) => header.toString().trim()); + headersToValidate = headersToValidate.filter((header: string) => header !== '#status#' && header !== '#errorDetails#'); if (!_.isEqual(expectedHeadersForTargetSheet, headersToValidate)) { throwError("COMMON", 400, "VALIDATION_ERROR", `Headers not according to the template in Target sheet ${worksheet.name}`); } @@ -675,6 +660,7 @@ async function validateCampaignBoundary(boundaries: any[], hierarchyType: any, t } } + async function validateProjectCampaignBoundaries(boundaries: any[], hierarchyType: any, tenantId: any, request: any): Promise { if (!request?.body?.CampaignDetails?.projectId) { if (boundaries) { @@ -712,9 +698,13 @@ async function validateBoundariesForTabs(CampaignDetails: any, resource: any, re // Fetch file response const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId, fileStoreIds: resource.fileStoreId }, "get"); const datas = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, localizedTab, true, undefined, localizationMap); - - const boundaryColumn = getLocalizedName(createAndSearch?.[resource.type]?.boundaryValidation?.column, localizationMap); - + var boundaryColumn: any; + if (resource?.additionalDetails?.source == 'microplan') { + boundaryColumn = getLocalizedName(createAndSearch?.[`${resource.type}Microplan`]?.boundaryValidation?.column, localizationMap); + } + else { + boundaryColumn = getLocalizedName(createAndSearch?.[resource.type]?.boundaryValidation?.column, localizationMap); + } // Initialize resource boundary codes as a set for uniqueness const resourceBoundaryCodesArray: any[] = []; var activeColumnName: any = null; @@ -739,6 +729,7 @@ async function validateBoundariesForTabs(CampaignDetails: any, resource: any, re const errorString = `The following boundary codes are not present in selected boundaries : ${missingBoundaries.join(', ')}` errors.push({ status: "BOUNDARYERROR", rowNumber: rowData.rowNumber, errorDetails: errorString }) } + validateFacilityBoundaryForLowestLevel(request, boundaries, rowData, errors, localizationMap); } if (errors?.length > 0) { request.body.ResourceDetails.status = resourceDataStatuses.invalid @@ -817,14 +808,16 @@ async function validateProjectCampaignResources(resources: any, request: any) { missingTypes.push(type); } } - - if (missingTypes.length > 0) { - const missingTypesMessage = `Missing resources of types: ${missingTypes.join(', ')}`; - throwError("COMMON", 400, "VALIDATION_ERROR", missingTypesMessage); + if ((!request?.body?.parentCampaign) || (request?.body?.parentCampaign && request?.body?.CampaignDetails?.boundaries && request.body.CampaignDetails.boundaries.length > 0)) { + if (missingTypes.length > 0) { + const missingTypesMessage = `Missing resources of types: ${missingTypes.join(', ')}`; + throwError("COMMON", 400, "VALIDATION_ERROR", missingTypesMessage); + } } if (request?.body?.CampaignDetails?.action === "create" && request?.body?.CampaignDetails?.resources) { - await validateResources(request.body.CampaignDetails.resources, request); + logger.info(`skipResourceCheckValidationBeforeCreateForLocalTesting flag is ${config.values.skipResourceCheckValidationBeforeCreateForLocalTesting }`); + !config.values.skipResourceCheckValidationBeforeCreateForLocalTesting && await validateResources(request.body.CampaignDetails.resources, request); } } @@ -833,33 +826,49 @@ async function validateProjectCampaignResources(resources: any, request: any) { function validateProjectCampaignMissingFields(CampaignDetails: any) { validateCampaignBodyViaSchema(campaignDetailsSchema, CampaignDetails) - const { startDate, endDate } = CampaignDetails; - if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) { - throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate"); - } - const today: any = Date.now(); - if (startDate <= today) { - throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); - } } function validateDraftProjectCampaignMissingFields(CampaignDetails: any) { validateCampaignBodyViaSchema(campaignDetailsDraftSchema, CampaignDetails) - const { startDate, endDate, action } = CampaignDetails; - if (action != "changeDates") { - if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) { - throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate"); +} + +async function validateParent(request: any, actionInUrl: any) { + if (request?.body?.CampaignDetails?.parentId) { + const tenantId = request.body.CampaignDetails?.tenantId + // const searchBodyForParent: any = { + // RequestInfo: request.body.RequestInfo, + const CampaignDetails = { + tenantId: tenantId, + ids: [request.body.CampaignDetails?.parentId] } - const today: any = Date.now(); - if (startDate <= today) { - throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); + // const req: any = replicateRequest(request, searchBodyForParent) + const parentSearchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) + if (Array.isArray(parentSearchResponse?.CampaignDetails)) { + if (actionInUrl == "create") { + if (parentSearchResponse?.CampaignDetails?.length > 0 && parentSearchResponse?.CampaignDetails?.[0]?.status == "created" && + parentSearchResponse?.CampaignDetails?.[0]?.isActive) { + request.body.parentCampaign = parentSearchResponse?.CampaignDetails[0] + } + else { + throwError("CAMPAIGN", 400, "PARENT_CAMPAIGN_ERROR", "Parent Campaign can't be inactive when creating child campaign"); + } + } + else { + if (parentSearchResponse?.CampaignDetails?.length > 0 && parentSearchResponse?.CampaignDetails?.[0]?.status == "created" && + !parentSearchResponse?.CampaignDetails?.[0]?.isActive) { + request.body.parentCampaign = parentSearchResponse?.CampaignDetails[0] + } + else { + throwError("CAMPAIGN", 400, "PARENT_CAMPAIGN_ERROR", "Parent Campaign can't be active when updating child campaign"); + } + + } } } } async function validateCampaignName(request: any, actionInUrl: any) { - const CampaignDetails = request.body.CampaignDetails; - const { campaignName, tenantId } = CampaignDetails; + const { campaignName, tenantId } = request.body.CampaignDetails; if (!campaignName) { throwError("COMMON", 400, "VALIDATION_ERROR", "campaignName is required"); } @@ -867,25 +876,38 @@ async function validateCampaignName(request: any, actionInUrl: any) { throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); } if (campaignName.length >= 2) { - const searchBody = { - RequestInfo: request.body.RequestInfo, - CampaignDetails: { + // const searchBody = { + // RequestInfo: request.body.RequestInfo, + const CampaignDetails = { tenantId: tenantId, - campaignName: campaignName + campaignName: campaignName, + status: [campaignStatuses.drafted, campaignStatuses.started, campaignStatuses.inprogress], + } + // } + if (request.body?.parentCampaign) { + if (request?.body?.CampaignDetails?.campaignName != request?.body?.parentCampaign?.campaignName) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_NOT_MATCHING_PARENT_ERROR", "Campaign name should be same as that of parent"); } } - const req: any = replicateRequest(request, searchBody) - const searchResponse: any = await searchProjectTypeCampaignService(req) + // const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) if (Array.isArray(searchResponse?.CampaignDetails)) { if (searchResponse?.CampaignDetails?.length > 0) { const allCampaigns = searchResponse?.CampaignDetails; logger.info(`campaignName to match : ${"'"}${campaignName}${"'"}`) - const campaignWithMatchingName: any = allCampaigns.find((campaign: any) => "'" + campaign?.campaignName + "'" == "'" + campaignName + "'") || null; - if (campaignWithMatchingName && actionInUrl == "create") { - throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); - } - else if (campaignWithMatchingName && actionInUrl == "update" && campaignWithMatchingName?.id != CampaignDetails?.id) { - throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + const matchingCampaigns: any[] = allCampaigns.filter((campaign: any) => campaign?.campaignName === campaignName); + for (const campaignWithMatchingName of matchingCampaigns) { + if (campaignWithMatchingName && actionInUrl == "create") { + if (!request.body.CampaignDetails?.parentId) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } + else if (campaignWithMatchingName?.id != request.body.CampaignDetails?.parentId) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } + } + else if (campaignWithMatchingName && actionInUrl == "update" && campaignWithMatchingName?.id != request.body.CampaignDetails?.id) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } } } } @@ -900,15 +922,15 @@ async function validateById(request: any) { if (!id) { throwError("COMMON", 400, "VALIDATION_ERROR", "id is required"); } - const searchBody = { - RequestInfo: request.body.RequestInfo, - CampaignDetails: { + // const searchBody = { + // RequestInfo: request.body.RequestInfo, + const CampaignDetails ={ tenantId: tenantId, ids: [id] } - } - const req: any = replicateRequest(request, searchBody) - const searchResponse: any = await searchProjectTypeCampaignService(req) + // } + // const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) if (Array.isArray(searchResponse?.CampaignDetails)) { if (searchResponse?.CampaignDetails?.length > 0) { logger.debug(`CampaignDetails : ${getFormattedStringForDebug(searchResponse?.CampaignDetails)}`); @@ -951,7 +973,7 @@ async function validateProjectType(request: any, projectType: any, tenantId: any } } const params = { tenantId: tenantId } - const searchResponse: any = await httpRequest(config.host.mdms + config?.paths?.mdms_search, searchBody, params); + const searchResponse: any = await httpRequest(config.host.mdmsV2 + config?.paths?.mdms_v1_search, searchBody, params); if (searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes && Array.isArray(searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes)) { const projectTypes = searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; if (!projectTypes.includes(projectType)) { @@ -1001,29 +1023,49 @@ async function validateChangeDatesRequest(request: any) { } async function validateCampaignBody(request: any, CampaignDetails: any, actionInUrl: any) { - const { hierarchyType, action, tenantId, boundaries, resources, projectType } = CampaignDetails; + const { hierarchyType, action, tenantId, resources, projectType } = CampaignDetails; if (action == "changeDates") { await validateChangeDatesRequest(request); } else if (action == "create") { validateProjectCampaignMissingFields(CampaignDetails); + await validateParent(request, actionInUrl) + validateBoundariesIfParentPresent(request); + validateProjectDatesForCampaign(request, CampaignDetails); await validateCampaignName(request, actionInUrl); if (tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is not matching with userInfo"); } await validateHierarchyType(request, hierarchyType, tenantId); await validateProjectType(request, projectType, tenantId); - await validateProjectCampaignBoundaries(boundaries, hierarchyType, tenantId, request); + await validateProjectCampaignBoundaries(request?.body?.boundariesCombined, hierarchyType, tenantId, request); await validateProjectCampaignResources(resources, request); + await validateProductVariant(request); } else { validateDraftProjectCampaignMissingFields(CampaignDetails); + await validateParent(request, actionInUrl); + validateBoundariesIfParentPresent(request); + validateProjectDatesForCampaign(request, CampaignDetails); await validateCampaignName(request, actionInUrl); await validateHierarchyType(request, hierarchyType, tenantId); await validateProjectType(request, projectType, tenantId); } } +function validateProjectDatesForCampaign(request: any, CampaignDetails: any) { + if (!request?.body?.parentCampaign) { + const { startDate, endDate } = CampaignDetails; + if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate"); + } + const today: any = Date.now(); + if (startDate <= today) { + throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); + } + } +} + async function validateProjectCampaignRequest(request: any, actionInUrl: any) { const CampaignDetails = request.body.CampaignDetails; const { id, action } = CampaignDetails; @@ -1038,11 +1080,20 @@ async function validateProjectCampaignRequest(request: any, actionInUrl: any) { if (!action) { throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails.action is required and must be either 'create' or 'draft'") } - if (!(action == "create" || action == "draft" || action == "changeDates")) { - throwError("COMMON", 400, "VALIDATION_ERROR", "action can only be create, draft or changeDates"); + if (!(action == "create" || action == "draft" || action == "changeDates" || action == "retry")) { + throwError("COMMON", 400, "VALIDATION_ERROR", "action can only be create, draft, retry or changeDates"); + } + if (actionInUrl == "retry") { + await validateForRetry(request); } if (actionInUrl == "update") { await validateById(request); + await validateIsActive(request); + } + if (actionInUrl == "create") { + if (!request?.body?.CampaignDetails?.isActive) { + request.body.CampaignDetails.isActive = true; + } } if (action == "changeDates" && actionInUrl == "create") { throwError("COMMON", 400, "VALIDATION_ERROR", "changeDates is not allowed during create"); @@ -1050,6 +1101,109 @@ async function validateProjectCampaignRequest(request: any, actionInUrl: any) { await validateCampaignBody(request, CampaignDetails, actionInUrl); } +async function validateForRetry(request: any) { + if (!request.body || !request.body.CampaignDetails) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails are missing in the request body"); + } + const { id, tenantId } = request.body.CampaignDetails; + if (!id) { + throwError("COMMON", 400, "VALIDATION_ERROR", "id is required"); + } + if (!tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); + } + // const searchBody = { + // RequestInfo: request.body.RequestInfo, + const CampaignDetails= { + tenantId: tenantId, + ids: [id] + } + // } + // const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) + if (Array.isArray(searchResponse?.CampaignDetails)) { + if (searchResponse?.CampaignDetails?.length > 0) { + logger.debug(`CampaignDetails : ${getFormattedStringForDebug(searchResponse?.CampaignDetails)}`); + request.body.ExistingCampaignDetails = searchResponse?.CampaignDetails[0]; + if (request.body.ExistingCampaignDetails?.status != campaignStatuses?.failed) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Campaign can only be retried in failed state.`); + } + request.body.CampaignDetails.status = campaignStatuses?.drafted; + var updatedInnerCampaignDetails = {} + enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) + request.body.CampaignDetails.campaignDetails = updatedInnerCampaignDetails; + const producerMessage: any = { + CampaignDetails: request?.body?.CampaignDetails + } + await produceModifiedMessages(producerMessage, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC); + + if (!request.body.CampaignDetails.additionalDetails.retryCycle) { + // If not present, initialize it as an empty array + request.body.CampaignDetails.additionalDetails.retryCycle = []; + } + + // Step 2: Push new data to the `retryCycle` array + request.body.CampaignDetails.additionalDetails.retryCycle.push({ + error: request.body.CampaignDetails.additionalDetails.error, + retriedAt: Date.now(), + failedAt: request.body.CampaignDetails.auditDetails.lastModifiedTime + }); + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND"); + } + } + else { + throwError("CAMPAIGN", 500, "CAMPAIGN_SEARCH_ERROR"); + } +} + +async function validateProductVariant(request: any) { + const deliveryRules = request?.body?.CampaignDetails?.deliveryRules; + + if (!Array.isArray(deliveryRules)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "deliveryRules must be an array"); + } + + deliveryRules.forEach((rule: any, index: number) => { + const productVariants = rule?.resources; + if (!Array.isArray(productVariants) || productVariants.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `deliveryRules[${index}].resources must be a non-empty array`); + } + }); + const pvarIds= getPvarIds(request?.body); + await validatePvarIds(pvarIds as string[]); + logger.info("Validated product variants successfully"); +} + +async function validatePvarIds(pvarIds: string[]) { + // Validate that pvarIds is not null, undefined, or empty, and that no element is null or undefined + if (!pvarIds?.length || pvarIds.some((id:any) => !id)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "productVariantId is required in every delivery rule's resources"); + } + + // Fetch product variants using the fetchProductVariants function + const allProductVariants = await fetchProductVariants(pvarIds); + + // Extract the ids of the fetched product variants + const fetchedIds = new Set(allProductVariants.map((pvar: any) => pvar?.id)); + + // Identify missing or invalid product variants + const missingPvarIds = pvarIds.filter((id: any) => !fetchedIds.has(id)); + + if (missingPvarIds.length) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid product variant ${missingPvarIds.length === 1 ? 'id' : 'ids'}: ${missingPvarIds.join(", ")}`); + } +} + + +async function validateIsActive(request: any) { + if (!request?.body?.CampaignDetails.isActive) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Can't update isActive") + } +} + + async function validateSearchProjectCampaignRequest(request: any) { const CampaignDetails = request.body.CampaignDetails; if (!CampaignDetails) { @@ -1183,9 +1337,12 @@ async function immediateValidationForTargetSheet(request: any, dataFromSheet: an if (columns.startsWith('__EMPTY')) { throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid column has some random data in Target Sheet ${key} at row number ${boundaryRow['!row#number!']}`); } + if (!request?.body?.parentCampaignObject && columns.endsWith('(OLD)')) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Target template downloaded from update campaign flow has been uploaded in create campaign flow") + } } if (!boundaryRow[root]) { - throwError("COMMON", 400, "VALIDATION_ERROR", ` ${root} column is empty in Target Sheet ${key} at row number ${boundaryRow['!row#number!']}`); + throwError("COMMON", 400, "VALIDATION_ERROR", ` ${root} column is empty in Target Sheet ${key} at row number ${boundaryRow['!row#number!']}. Please upload from downloaded template only.`); } } } @@ -1205,7 +1362,7 @@ function validateAllDistrictTabsPresentOrNot(request: any, dataFromSheet: any, d logger.debug("districts present in user filled sheet (exclude first two tabs): " + getFormattedStringForDebug(tabsFromTargetSheet)); if (tabsFromTargetSheet.length - tabsIndex !== tabsOfDistrict.length) { - throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tabs uplaoded by user is either less or more than the ${differentTabsBasedOnLevel} in the boundary system `) + throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tabs uploaded by user is either less or more than the ${differentTabsBasedOnLevel} in the boundary system. Please upload from downloaded template only.`); } else { for (let index = tabsIndex; index < tabsFromTargetSheet.length; index++) { const tab = tabsFromTargetSheet[index]; // Get the current tab @@ -1213,6 +1370,23 @@ function validateAllDistrictTabsPresentOrNot(request: any, dataFromSheet: any, d throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tab ${tab} not present in the Target Sheet Uploaded`); } } + const MissingDistricts: any = []; + const campaignBoundaries = request?.body?.campaignBoundaries; + if (campaignBoundaries && campaignBoundaries?.length > 0) { + const districtsLocalised = campaignBoundaries + .filter((data: any) => getLocalizedName(`${request?.body?.ResourceDetails?.hierarchyType}_${data.type.toUpperCase()}`, localizationMap).toLocaleLowerCase() == differentTabsBasedOnLevel.toLowerCase()) + .map((data: any) => getLocalizedName(data?.code, localizationMap)) || []; + + tabsOfDistrict.forEach((tab: any) => { + if (!districtsLocalised.includes(tab)) { + MissingDistricts.push(tab); + } + }); + } + + if (MissingDistricts.length > 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Districts ${MissingDistricts.join(', ')} not present in the Target Sheet Uploaded`); + } } } @@ -1223,6 +1397,109 @@ function validateSearchProcessTracksRequest(request: any) { } } +async function validateMicroplanRequest(request: any) { + const { tenantId, campaignId, planConfigurationId } = request.body.MicroplanDetails; + if (!tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); + } + if (!campaignId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "campignId is required"); + } + if (!planConfigurationId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "planConfigurationId is required"); + } + logger.info("All required fields are present"); + + await validateCampaignFromId(request); + await validatePlanFacility(request); +} + +async function validatePlanFacility(request: any) { + const planConfigSearchResponse = await planConfigSearch(request); + const planFacilitySearchResponse = await planFacilitySearch(request); + + if (planFacilitySearchResponse.PlanFacility.length === 0) { + throwError("COMMAN", 400, "Plan facilities not found"); + } + + request.body.PlanFacility = planFacilitySearchResponse.PlanFacility; + request.body.planConfig = planConfigSearchResponse.PlanConfiguration[0]; +} + +async function validateCampaignFromId(request: any) { + const { tenantId, campaignId } = request.body.MicroplanDetails; + + // const searchBody = { + // RequestInfo: request.body.RequestInfo, + const campaignDetails = { + tenantId: tenantId, + ids: [campaignId] + } + // } + + // const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(campaignDetails); + + if (searchResponse?.CampaignDetails?.length == 0) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND"); + } + + logger.info("Campaign Found"); + request.body.CampaignDetails = searchResponse?.CampaignDetails[0]; +} + + +function validateBoundarySheetDataInCreateFlow(boundarySheetData: any, localizedHeadersOfBoundarySheet: any) { + const firstColumnValues = new Set(); + const firstColumn = localizedHeadersOfBoundarySheet[0]; + + boundarySheetData.forEach((obj: any, index: number) => { + let firstEmptyFound = false; + // Collect value from the first column + if (obj[firstColumn]) { + firstColumnValues.add(obj[firstColumn]); + } + if (firstColumnValues.size > 1) { + throwError("BOUNDARY", 400, "BOUNDARY_SHEET_FIRST_COLUMN_INVALID_ERROR", + `Data is invalid: The "${firstColumn}" column must contain only one unique value across all rows.`); + } + + for (const header of localizedHeadersOfBoundarySheet) { + const value = obj[header]; + + if (!value) { + // Mark that an empty value has been found for the first time + firstEmptyFound = true; + } else if (firstEmptyFound) { + // If a non-empty value is found after an empty value in the expected order, throw an error + throwError("BOUNDARY", 400, "BOUNDARY_SHEET_UPLOADED_INVALID_ERROR", + `Data is invalid in object at index ${index + 2}: Non-empty value for key "${header}" found after an empty value in the left.`); + } + } + }); +} + +export function validateEmptyActive(data: any, type: string, localizationMap?: { [key: string]: string }) { + let isActiveRowsZero = true; + const activeColumnName = createAndSearch?.[type]?.activeColumnName ? getLocalizedName(createAndSearch?.[type]?.activeColumnName, localizationMap) : null; + if(Array.isArray(data)){ + data.forEach((item: any) => { + const active = activeColumnName ? item[activeColumnName] : "Active"; + if (active == "Active") { + isActiveRowsZero = false; + return; + } + }); + } + else{ + // Data is not coming from a single sheet so no require for this active check + isActiveRowsZero = false; + } + if(isActiveRowsZero){ + throwError("COMMON", 400, "VALIDATION_ERROR", "At least one active row is required"); + } +} + export { fetchBoundariesInChunks, @@ -1239,5 +1516,9 @@ export { validateTargetSheetData, immediateValidationForTargetSheet, validateBoundaryOfResouces, - validateSearchProcessTracksRequest + validateSearchProcessTracksRequest, + validateParent, + validateForRetry, + validateBoundarySheetDataInCreateFlow, + validateMicroplanRequest } diff --git a/health-services/project-factory/src/server/validators/genericValidator.ts b/health-services/project-factory/src/server/validators/genericValidator.ts index 245579d6134..5c8ed266a53 100644 --- a/health-services/project-factory/src/server/validators/genericValidator.ts +++ b/health-services/project-factory/src/server/validators/genericValidator.ts @@ -2,14 +2,14 @@ import * as express from "express"; import { logger } from "../utils/logger"; import Ajv from "ajv"; -import config from "../config/index"; -import { httpRequest } from "../utils/request"; import { getBoundaryRelationshipData, throwError } from "../utils/genericUtils"; import { validateFilters } from "./campaignValidators"; import { generateRequestSchema } from "../config/models/generateRequestSchema"; import { persistTrack } from "../utils/processTrackUtils"; import { processTrackTypes, processTrackStatuses, campaignStatuses } from "../config/constants"; import { validateMappingId } from "../utils/campaignMappingUtils"; +import { searchBoundaryRelationshipDefinition } from "../api/coreApis"; +import { BoundaryModels } from "../models"; // Function to validate data against a JSON schema function validateDataWithSchema(data: any, schema: any): { isValid: boolean; error: any | null | undefined } { @@ -202,18 +202,18 @@ function validatedProjectResponseAndUpdateId(projectResponse: any, projectBody: // Function to validate the hierarchy type async function validateHierarchyType(request: any, hierarchyType: any, tenantId: any) { - const searchBody = { - RequestInfo: request?.body?.RequestInfo, - BoundaryTypeHierarchySearchCriteria: { - "tenantId": tenantId, - "limit": 5, - "offset": 0, - "hierarchyType": hierarchyType + + const BoundaryTypeHierarchySearchCriteria: BoundaryModels.BoundaryHierarchyDefinitionSearchCriteria={ + BoundaryTypeHierarchySearchCriteria:{ + tenantId, + hierarchyType } - } - const response = await httpRequest(config.host.boundaryHost + config.paths.boundaryHierarchy, searchBody); + }; + const response:BoundaryModels.BoundaryHierarchyDefinitionResponse =await searchBoundaryRelationshipDefinition(BoundaryTypeHierarchySearchCriteria); + if (response?.BoundaryHierarchy && Array.isArray(response?.BoundaryHierarchy) && response?.BoundaryHierarchy?.length > 0) { logger.info(`hierarchyType : ${hierarchyType} :: got validated`); + request.body.hierarchyType = response?.BoundaryHierarchy?.[0]; } else { throwError(`CAMPAIGN`, 400, "VALIDATION_ERROR", `hierarchyType ${hierarchyType} not found`); diff --git a/health-services/project-factory/src/server/validators/microplanValidators.ts b/health-services/project-factory/src/server/validators/microplanValidators.ts new file mode 100644 index 00000000000..7d8d7658bf3 --- /dev/null +++ b/health-services/project-factory/src/server/validators/microplanValidators.ts @@ -0,0 +1,300 @@ +import { getBoundaryTabName } from "../utils/boundaryUtils"; +import createAndSearch from "../config/createAndSearch"; +import { getLocalizedName } from "../utils/campaignUtils"; +import { resourceDataStatuses } from "../config/constants"; +import config from "../config"; + +export function validatePhoneNumberSheetWise(datas: any[], localizationMap: any, rowMapping: any) { + for (const data of datas) { + const phoneColumn = getLocalizedName("HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER_MICROPLAN", localizationMap); + if (data[phoneColumn]) { + let phoneNumber = data[phoneColumn].toString(); + + // Check if the phone number is numeric and has exactly 10 digits + const isNumeric = /^\d+$/.test(phoneNumber); + if (phoneNumber.length !== 10 || !isNumeric) { + const row = data["!row#number!"]; + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Contact number’ entered is invalid, it should be a 10-digit number and contain only digits. Please update and re-upload."); + } + } else { + const row = data["!row#number!"]; + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Contact number’ is a mandatory field in the file. Please update and re-upload."); + } + } +} + + +export function validateEmailSheetWise(datas: any[], localizationMap: any, rowMapping: any) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // Simple email regex pattern + + for (const data of datas) { + const emailColumn = getLocalizedName("HCM_ADMIN_CONSOLE_USER_EMAIL_MICROPLAN", localizationMap); + if (data[emailColumn]) { + let email = data[emailColumn].toString(); + + if (!emailRegex.test(email)) { // Validate email format with regex + const row = data["!row#number!"]; + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Email’ entered is invalid. Please provide a valid email address and re-upload."); + } + } + } +} + +export function validateNameSheetWise(datas: any[], localizationMap: any, rowMapping: any) { + for (const data of datas) { + const nameColumn = getLocalizedName("HCM_ADMIN_CONSOLE_USER_NAME_MICROPLAN", localizationMap); + if (data[nameColumn]) { + var name = data[nameColumn]; + name = name.toString(); + const row = data["!row#number!"]; + + // Check name length + if (name.length > 128 || name.length < 2) { + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Name’ should be between 2 to 128 characters. Please update and re-upload"); + } + else { + // Check if name contains at least one alphabetic character + const hasAlphabetic = /[a-zA-Z]/.test(name); + if (!hasAlphabetic) { + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Name’ should contain at least one alphabetic character. Please update and re-upload"); + } + } + + } else { + const row = data["!row#number!"]; + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Name’ is a mandatory field in the file. Please update and re-upload"); + } + } +} + + +export function validateUserForMicroplan(data: any, sheetName: any, request: any, errorMap: any, newSchema: any, rowMapping: any, localizationMap: any) { + if (data?.length > 0) { + validatePhoneNumberSheetWise(data, localizationMap, rowMapping); + validateEmailSheetWise(data, localizationMap, rowMapping); + validateNameSheetWise(data, localizationMap, rowMapping); + validateUniqueSheetWise(newSchema, data, request, rowMapping, localizationMap); + } + else { + errorMap[sheetName] = { 2: ["Data rows cannot be empty"] }; + } +} + +export function validateUniqueSheetWise(schema: any, data: any[], request: any, rowMapping: any, localizationMap: any) { + if (schema?.unique) { + const uniqueElements = schema.unique; + + for (const element of uniqueElements) { + const uniqueMap = new Map(); + + // Iterate over each data object and check uniqueness + for (const item of data) { + const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName; + const localizedUniqueIdentifierColumnName = getLocalizedName(uniqueIdentifierColumnName, localizationMap); + const value = item[element]; + const rowNum = item['!row#number!']; + if (!localizedUniqueIdentifierColumnName || !item[localizedUniqueIdentifierColumnName] && value != undefined) { + if (uniqueMap.has(value)) { + if (!rowMapping[rowNum]) { + rowMapping[rowNum] = []; + } + rowMapping[rowNum].push(`Duplicate value '${value}' found for '${element}'`); + } + // Add the value to the map + uniqueMap.set(value, rowNum); + } + } + } + } +} + +export function validateTargetsForMicroplanCampaigns(data: any, errors: any, localizedTargetColumnNames: any, localizationMap?: { [key: string]: string }) { + for (const key in data) { + if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { + if (Array.isArray(data[key])) { + const boundaryData = data[key]; + boundaryData.forEach((obj: any, index: number) => { + var totalTarget = 0, totalTargetSumFromColumns = 0; + for (let i = 0; i < localizedTargetColumnNames.length; i++) { + const targetColumn = localizedTargetColumnNames[i]; + const target = obj[targetColumn]; + if (target !== 0 && !target) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in column '${targetColumn}' can’t be empty, please update the data and re-upload`, + sheetName: key + }); + } else if (typeof target !== 'number') { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in column '${targetColumn}' must be a whole number from 1 to 100000000. Please update the data and re-upload.`, + sheetName: key + }); + } else if (target < 1 || target > 100000000) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in column '${targetColumn}' must be a whole number from 1 to 100000000. Please update the data and re-upload.`, + sheetName: key + }); + } else if (!Number.isInteger(target)) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in column '${targetColumn}' must be a whole number from 1 to 100000000. Please update the data and re-upload.`, + sheetName: key + }); + } + if (i == 0) { + totalTarget = target; + } + else { + totalTargetSumFromColumns += target; + } + } + if (totalTargetSumFromColumns > totalTarget) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in other target columns must be less than or equal to '${localizedTargetColumnNames[0]}'`, + sheetName: key + }); + } + }); + } + } + } +} + +export function validateLatLongForMicroplanCampaigns(data: any, errors: any, localizationMap?: { [key: string]: string }) { + for (const key in data) { + if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { + if (Array.isArray(data[key])) { + const boundaryData = data[key]; + boundaryData.forEach((obj: any, index: number) => { + for (const column of Object.keys(obj)) { + if (column.toLowerCase().includes('latitude') || column.toLowerCase().includes('longitude')) { + const value = obj[column]; + if (typeof value !== 'number') { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in column '${column}' must comply with the guideline structure, please update the data and re-upload`, + sheetName: key + }); + } + } + } + }); + } + } + } +} + + +function validateLatLongForFacility(data: any, errors: any) { + for (const column of Object.keys(data)) { + if (column.toLowerCase().includes('latitude') || column.toLowerCase().includes('longitude')) { + const value = data[column]; + if (typeof value !== 'number') { + errors.push({ + status: "INVALID", + rowNumber: data["!row#number!"], + errorDetails: `Data in column '${column}' must comply with the guideline structure, please update the data and re-upload` + }); + } + } + } +}; + +export function validateMicroplanFacility(request: any, data: any, localizationMap: any) { + const uniqueIdentifierColumnName = getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap); + const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; + var errors: any = [] + data.forEach((item: any) => { + if (activeColumnName) { + if (!item?.[activeColumnName]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${activeColumnName} column can’t be empty, please update the data and re-upload` }); + } + else if (item?.[activeColumnName] != "Active" && item?.[activeColumnName] != "Inactive") { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${activeColumnName} column must be equal to one of the allowed values. Allowed values are Active, Inactive` }); + } + } + const active = activeColumnName ? item[activeColumnName] : "Active"; + if (active == "Active" || !item?.[uniqueIdentifierColumnName]) { + enrichErrorForFcailityMicroplan(request, item, errors, localizationMap); + validateLatLongForFacility(item, errors); + } + }); + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + if (request?.body?.sheetErrorDetails && Array.isArray(request?.body?.sheetErrorDetails) && request?.body?.sheetErrorDetails?.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid; + } +} + +function enrichErrorForFcailityMicroplan(request: any, item: any, errors: any = [], localizationMap?: { [key: string]: string }) { + const projectType = request?.body?.projectTypeCode; + const nameColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_NAME_MICROPLAN", localizationMap); + if (!item?.[nameColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${nameColumn} column can’t be empty, please update the data and re-upload` }) + } + const facilityTypeColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_TYPE_MICROPLAN", localizationMap); + if (!item?.[facilityTypeColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityTypeColumn} column can’t be empty, please update the data and re-upload` }) + } + const faciltyStatusColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_STATUS_MICROPLAN", localizationMap); + if (!item?.[faciltyStatusColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${faciltyStatusColumn} column can’t be empty, please update the data and re-upload` }) + } + const facilityCapacityColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN_${projectType}`, localizationMap); + if (!item?.[facilityCapacityColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column can’t be empty, please update the data and re-upload` }) + } + else if (typeof (item?.[facilityCapacityColumn]) != "number") { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column must be a number in between 1 and 100000000` }) + } + else if (item?.[facilityCapacityColumn] < 1 || item?.[facilityCapacityColumn] > 100000000) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column must be a number in between 1 and 100000000` }) + } + const fixedPostColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_FIXED_POST_MICROPLAN", localizationMap); + if (request?.body?.showFixedPost && !item?.[fixedPostColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${fixedPostColumn} column can’t be empty, please update the data and re-upload` }) + } + const boundaryColumn = getLocalizedName("HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN", localizationMap); + if (!item?.[boundaryColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${boundaryColumn} column can’t be empty, please update the data and re-upload` }) + } +} + +export function validateFacilityBoundaryForLowestLevel(request: any, boundaries: any, rowData: any, errors: any = [], localizationMap?: { [key: string]: string }) { + if (request?.body?.ResourceDetails?.type == "facility" && request?.body?.ResourceDetails?.additionalDetails?.source == "microplan") { + const hierarchy = request?.body?.hierarchyType?.boundaryHierarchy + const lastLevel = hierarchy?.[hierarchy.length - 1]?.boundaryType + for (const data of rowData?.boundaryCodes) { + const boundaryFromBoundariesType = boundaries.find((boundary: any) => boundary.code == data)?.type + if (boundaryFromBoundariesType != lastLevel) { + errors.push({ status: "INVALID", rowNumber: rowData?.rowNumber, errorDetails: `${data} is not a ${lastLevel} level boundary` }) + } + } + } +} diff --git a/health-services/project-factory/yarn.lock b/health-services/project-factory/yarn.lock index 4e9c73bf0f7..2f75dbe7f43 100644 --- a/health-services/project-factory/yarn.lock +++ b/health-services/project-factory/yarn.lock @@ -4,315 +4,308 @@ "@ampproject/remapping@^2.2.0": version "2.3.0" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2": - version "7.24.2" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" - integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== dependencies: - "@babel/highlight" "^7.24.2" + "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/compat-data@^7.23.5": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz" - integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== +"@babel/compat-data@^7.25.2": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" + integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.8.0": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz" - integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA== +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.5" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.24.5" - "@babel/helpers" "^7.24.5" - "@babel/parser" "^7.24.5" - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.5" - "@babel/types" "^7.24.5" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.5", "@babel/generator@^7.7.2": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz" - integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== +"@babel/generator@^7.25.0", "@babel/generator@^7.25.6", "@babel/generator@^7.7.2": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" + integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== dependencies: - "@babel/types" "^7.24.5" + "@babel/types" "^7.25.6" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== +"@babel/helper-compilation-targets@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" + integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" + "@babel/compat-data" "^7.25.2" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-module-imports@^7.24.3": - version "7.24.3" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz" - integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== - dependencies: - "@babel/types" "^7.24.0" - -"@babel/helper-module-transforms@^7.24.5": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz" - integrity sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.24.3" - "@babel/helper-simple-access" "^7.24.5" - "@babel/helper-split-export-declaration" "^7.24.5" - "@babel/helper-validator-identifier" "^7.24.5" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz" - integrity sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ== - -"@babel/helper-simple-access@^7.24.5": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz" - integrity sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ== - dependencies: - "@babel/types" "^7.24.5" - -"@babel/helper-split-export-declaration@^7.24.5": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz" - integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q== - dependencies: - "@babel/types" "^7.24.5" - -"@babel/helper-string-parser@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz" - integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== - -"@babel/helper-validator-identifier@^7.24.5": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz" - integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== - -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== - -"@babel/helpers@^7.24.5": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz" - integrity sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q== - dependencies: - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.5" - "@babel/types" "^7.24.5" - -"@babel/highlight@^7.24.2": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz" - integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw== - dependencies: - "@babel/helper-validator-identifier" "^7.24.5" +"@babel/helper-module-imports@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-module-transforms@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" + integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== + dependencies: + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.2" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.8.0": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" + integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== + +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-string-parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" + integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== + +"@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== + +"@babel/helpers@^7.25.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" + integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== + dependencies: + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" + +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.7" chalk "^2.4.2" js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz" - integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.25.6": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" + integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== + dependencies: + "@babel/types" "^7.25.6" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-bigint@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-import-meta@^7.8.3": +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz#6d4c78f042db0e82fd6436cd65fec5dc78ad2bde" + integrity sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.8" + +"@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz" - integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d" + integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4": version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz" - integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== - dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": - version "7.24.0" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz" - integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.24.0" - "@babel/types" "^7.24.0" - -"@babel/traverse@^7.24.5": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz" - integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== - dependencies: - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.5" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.24.5" - "@babel/parser" "^7.24.5" - "@babel/types" "^7.24.5" + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz#04db9ce5a9043d9c635e75ae7969a2cd50ca97ff" + integrity sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.8" + +"@babel/template@^7.25.0", "@babel/template@^7.3.3": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" + integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.25.0" + "@babel/types" "^7.25.0" + +"@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" + integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.6" + "@babel/parser" "^7.25.6" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz" - integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6", "@babel/types@^7.3.3": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" + integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== dependencies: - "@babel/helper-string-parser" "^7.24.1" - "@babel/helper-validator-identifier" "^7.24.5" + "@babel/helper-string-parser" "^7.24.8" + "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": version "0.2.3" - resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@colors/colors@^1.6.0", "@colors/colors@1.6.0": +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": version "1.6.0" - resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" - resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: "@jridgewell/trace-mapping" "0.3.9" "@dabh/diagnostics@^2.0.2": version "2.0.3" - resolved "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== dependencies: colorspace "1.1.x" @@ -321,7 +314,7 @@ "@eslint/eslintrc@^0.2.2": version "0.2.2" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76" integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ== dependencies: ajv "^6.12.4" @@ -337,7 +330,7 @@ "@fast-csv/format@4.3.5": version "4.3.5" - resolved "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz" + resolved "https://registry.yarnpkg.com/@fast-csv/format/-/format-4.3.5.tgz#90d83d1b47b6aaf67be70d6118f84f3e12ee1ff3" integrity sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A== dependencies: "@types/node" "^14.0.1" @@ -349,7 +342,7 @@ "@fast-csv/parse@4.3.6": version "4.3.6" - resolved "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz" + resolved "https://registry.yarnpkg.com/@fast-csv/parse/-/parse-4.3.6.tgz#ee47d0640ca0291034c7aa94039a744cfb019264" integrity sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA== dependencies: "@types/node" "^14.0.1" @@ -362,12 +355,12 @@ "@ioredis/commands@^1.1.1": version "1.2.0" - resolved "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== "@isaacs/cliui@^8.0.2": version "8.0.2" - resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== dependencies: string-width "^5.1.2" @@ -379,7 +372,7 @@ "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" - resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: camelcase "^5.3.1" @@ -390,12 +383,12 @@ "@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": version "0.1.3" - resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== "@jest/console@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: "@jest/types" "^29.6.3" @@ -407,7 +400,7 @@ "@jest/core@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== dependencies: "@jest/console" "^29.7.0" @@ -441,7 +434,7 @@ "@jest/environment@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== dependencies: "@jest/fake-timers" "^29.7.0" @@ -451,14 +444,14 @@ "@jest/expect-utils@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== dependencies: jest-get-type "^29.6.3" "@jest/expect@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== dependencies: expect "^29.7.0" @@ -466,7 +459,7 @@ "@jest/fake-timers@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== dependencies: "@jest/types" "^29.6.3" @@ -478,7 +471,7 @@ "@jest/globals@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: "@jest/environment" "^29.7.0" @@ -488,7 +481,7 @@ "@jest/reporters@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" @@ -518,14 +511,14 @@ "@jest/schemas@^29.6.3": version "29.6.3" - resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== dependencies: "@sinclair/typebox" "^0.27.8" "@jest/source-map@^29.6.3": version "29.6.3" - resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: "@jridgewell/trace-mapping" "^0.3.18" @@ -534,7 +527,7 @@ "@jest/test-result@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: "@jest/console" "^29.7.0" @@ -544,7 +537,7 @@ "@jest/test-sequencer@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== dependencies: "@jest/test-result" "^29.7.0" @@ -554,7 +547,7 @@ "@jest/transform@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: "@babel/core" "^7.11.6" @@ -575,7 +568,7 @@ "@jest/types@^29.6.3": version "29.6.3" - resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: "@jest/schemas" "^29.6.3" @@ -587,7 +580,7 @@ "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== dependencies: "@jridgewell/set-array" "^1.2.1" @@ -596,38 +589,38 @@ "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/set-array@^1.2.1": version "1.2.1" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@npmcli/agent@^2.0.0": version "2.2.2" - resolved "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz" + resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-2.2.2.tgz#967604918e62f620a648c7975461c9c9e74fc5d5" integrity sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og== dependencies: agent-base "^7.1.0" @@ -638,58 +631,58 @@ "@npmcli/fs@^3.1.0": version "3.1.1" - resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-3.1.1.tgz#59cdaa5adca95d135fc00f2bb53f5771575ce726" integrity sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg== dependencies: semver "^7.3.5" "@pkgjs/parseargs@^0.11.0": version "0.11.0" - resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@sinclair/typebox@^0.27.8": version "0.27.8" - resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== "@sinonjs/commons@^3.0.0": version "3.0.1" - resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" "@sinonjs/fake-timers@^10.0.2": version "10.3.0" - resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== dependencies: "@sinonjs/commons" "^3.0.0" "@tsconfig/node10@^1.0.7": version "1.0.11" - resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": version "1.0.11" - resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== "@tsconfig/node14@^1.0.0": version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": version "1.0.4" - resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@types/babel__core@^7.1.14": version "7.20.5" - resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== dependencies: "@babel/parser" "^7.20.7" @@ -700,29 +693,29 @@ "@types/babel__generator@*": version "7.6.8" - resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": version "7.4.4" - resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.20.5" - resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz" - integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== dependencies: "@babel/types" "^7.20.7" "@types/body-parser@*": version "1.19.5" - resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== dependencies: "@types/connect" "*" @@ -730,22 +723,22 @@ "@types/compression@1.7.5": version "1.7.5" - resolved "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz" + resolved "https://registry.yarnpkg.com/@types/compression/-/compression-1.7.5.tgz#0f80efef6eb031be57b12221c4ba6bc3577808f7" integrity sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg== dependencies: "@types/express" "*" "@types/connect@*": version "3.4.38" - resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== dependencies: "@types/node" "*" "@types/express-serve-static-core@^4.17.33": - version "4.19.0" - resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz" - integrity sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ== + version "4.19.5" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz#218064e321126fcf9048d1ca25dd2465da55d9c6" + integrity sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg== dependencies: "@types/node" "*" "@types/qs" "*" @@ -754,7 +747,7 @@ "@types/express@*", "@types/express@4.17.21": version "4.17.21" - resolved "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== dependencies: "@types/body-parser" "*" @@ -764,64 +757,64 @@ "@types/graceful-fs@^4.1.3": version "4.1.9" - resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== dependencies: "@types/node" "*" "@types/hash-sum@1.0.2": version "1.0.2" - resolved "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/@types/hash-sum/-/hash-sum-1.0.2.tgz#32e6e4343ee25914b2a3822f27e8e641ca534f63" integrity sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw== "@types/helmet@0.0.47": version "0.0.47" - resolved "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.47.tgz" + resolved "https://registry.yarnpkg.com/@types/helmet/-/helmet-0.0.47.tgz#ec5161541b649142205b7c558bca14801c5ce129" integrity sha512-TcHA/djjdUtrMtq/QAayVLrsgjNNZ1Uhtz0KhfH01mrmjH44E54DA1A0HNbwW0H/NBFqV+tGMo85ACuEhMXcdg== dependencies: "@types/express" "*" "@types/http-errors@*": version "2.0.4" - resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== "@types/http-proxy-middleware@^1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz#4370a52766782e9c4f0be2ef79c3dd47aef5f428" integrity sha512-/s8lFX6rT43hSPqjjD8KNuu0SkPKY7uIdR6u9DCxVqCRhAvfKxGbVOixJsAT2mdpSnCyrGFAGoB39KFh6tmRxw== dependencies: http-proxy-middleware "*" -"@types/http-proxy@^1.17.10": - version "1.17.14" - resolved "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz" - integrity sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w== +"@types/http-proxy@^1.17.15": + version "1.17.15" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36" + integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ== dependencies: "@types/node" "*" "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.6" - resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== "@types/istanbul-lib-report@*": version "3.0.3" - resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": version "3.0.4" - resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== dependencies: "@types/istanbul-lib-report" "*" "@types/jaeger-client@^3.18.7": version "3.18.7" - resolved "https://registry.npmjs.org/@types/jaeger-client/-/jaeger-client-3.18.7.tgz" + resolved "https://registry.yarnpkg.com/@types/jaeger-client/-/jaeger-client-3.18.7.tgz#19315eb1616d85b84210da5df01b4a62c219c5b0" integrity sha512-ktEWbcM8faJY5UNEmffnvavjIJ9noNCD7clD9hAZIuQt6QMv0T97kiveH0mbvBNr9SPZXmkidOu/3UWgSy89tQ== dependencies: "@types/node" "*" @@ -830,44 +823,51 @@ "@types/jest@29.5.12": version "29.5.12" - resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== dependencies: expect "^29.0.0" pretty-format "^29.0.0" "@types/lodash@^4.17.5": - version "4.17.5" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz" - integrity sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw== + version "4.17.7" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.7.tgz#2f776bcb53adc9e13b2c0dfd493dfcbd7de43612" + integrity sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA== "@types/mime@^1": version "1.3.5" - resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== "@types/morgan@1.9.9": version "1.9.9" - resolved "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz" + resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.9.9.tgz#d60dec3979e16c203a000159daa07d3fb7270d7f" integrity sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ== dependencies: "@types/node" "*" -"@types/node@*", "@types/node@20.11.29": +"@types/node@*": + version "22.5.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.5.tgz#52f939dd0f65fc552a4ad0b392f3c466cc5d7a44" + integrity sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA== + dependencies: + undici-types "~6.19.2" + +"@types/node@20.11.29": version "20.11.29" - resolved "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.29.tgz#431253cede34f392d6aaf7acad427b9c23aa60f6" integrity sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA== dependencies: undici-types "~5.26.4" "@types/node@^14.0.1": version "14.18.63" - resolved "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b" integrity sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ== "@types/pg@8.11.3": version "8.11.3" - resolved "https://registry.npmjs.org/@types/pg/-/pg-8.11.3.tgz" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.11.3.tgz#f55c81b5ecdb6901636946eccfc7aac5dfc6b840" integrity sha512-xocw4LvpDcj/Ta7bN52tLZm34mso5SZ0Q8fVC0UtD8s85Itip3YHvBeYZhBmC0OThpdOujHsxXtRbEIRxqXPXg== dependencies: "@types/node" "*" @@ -875,18 +875,18 @@ pg-types "^4.0.1" "@types/qs@*": - version "6.9.15" - resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz" - integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg== + version "6.9.16" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" + integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== "@types/range-parser@*": version "1.2.7" - resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== "@types/send@*": version "0.17.4" - resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== dependencies: "@types/mime" "^1" @@ -894,7 +894,7 @@ "@types/serve-static@*": version "1.15.7" - resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: "@types/http-errors" "*" @@ -903,56 +903,56 @@ "@types/stack-utils@^2.0.0": version "2.0.3" - resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== "@types/strip-bom@^3.0.0": version "3.0.0" - resolved "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" integrity sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ== "@types/strip-json-comments@0.0.30": version "0.0.30" - resolved "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz" + resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== "@types/triple-beam@^1.3.2": version "1.3.5" - resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== "@types/uuid@9.0.8": version "9.0.8" - resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== "@types/xlsx@0.0.36": version "0.0.36" - resolved "https://registry.npmjs.org/@types/xlsx/-/xlsx-0.0.36.tgz" + resolved "https://registry.yarnpkg.com/@types/xlsx/-/xlsx-0.0.36.tgz#b5062003e5c5374ab4f08fdd3bf69da4d4013af8" integrity sha512-mvfrKiKKMErQzLMF8ElYEH21qxWCZtN59pHhWGmWCWFJStYdMWjkDSAy6mGowFxHXaXZWe5/TW7pBUiWclIVOw== dependencies: xlsx "*" "@types/yargs-parser@*": version "21.0.3" - resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^17.0.8": - version "17.0.32" - resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz" - integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== dependencies: "@types/yargs-parser" "*" abbrev@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: mime-types "~2.1.34" @@ -960,39 +960,41 @@ accepts@~1.3.5, accepts@~1.3.8: acorn-jsx@^5.3.1: version "5.3.2" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^8.1.1: - version "8.3.2" - resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz" - integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^7.4.0: +acorn@^7.4.0: version "7.4.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.4.1: - version "8.11.3" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +acorn@^8.11.0, acorn@^8.4.1: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== adler-32@~1.3.0: version "1.3.1" - resolved "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz" + resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2" integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A== agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1: version "7.1.1" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== dependencies: debug "^4.3.4" aggregate-error@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== dependencies: clean-stack "^2.0.0" @@ -1000,22 +1002,12 @@ aggregate-error@^3.0.0: ajv-errors@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-3.0.0.tgz#e54f299f3a3d30fe144161e5f0d8d51196c527bc" integrity sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ== -ajv@^6.10.0: - version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^6.12.4: +ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" @@ -1024,81 +1016,74 @@ ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1, ajv@^8.16.0: - version "8.16.0" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz" - integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== dependencies: fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" - uri-js "^4.4.1" ansi-color@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/ansi-color/-/ansi-color-0.2.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-color/-/ansi-color-0.2.1.tgz#3e75c037475217544ed763a8db5709fa9ae5bf9a" integrity sha512-bF6xLaZBLpOQzgYUtYEhJx090nPSZk1BQ/q2oyBK9aMMcJHzx9uXGCjI2Y+LebsN4Jwoykr0V9whbPiogdyHoQ== ansi-colors@^4.1.1: version "4.1.3" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== ansi-escapes@^4.2.1: version "4.3.2" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" ansi-styles@^5.0.0: version "5.2.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== ansi-styles@^6.1.0: version "6.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.3" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" @@ -1106,12 +1091,12 @@ anymatch@^3.0.3, anymatch@~3.1.2: aproba@^1.0.3: version "1.2.0" - resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== archiver-utils@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== dependencies: glob "^7.1.4" @@ -1127,7 +1112,7 @@ archiver-utils@^2.1.0: archiver-utils@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-3.0.4.tgz#a0d201f1cf8fce7af3b5a05aea0a337329e96ec7" integrity sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw== dependencies: glob "^7.2.3" @@ -1143,7 +1128,7 @@ archiver-utils@^3.0.4: archiver@^5.0.0: version "5.3.2" - resolved "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.2.tgz#99991d5957e53bd0303a392979276ac4ddccf3b0" integrity sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw== dependencies: archiver-utils "^2.1.0" @@ -1156,7 +1141,7 @@ archiver@^5.0.0: are-we-there-yet@~1.1.2: version "1.1.7" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== dependencies: delegates "^1.0.0" @@ -1164,51 +1149,46 @@ are-we-there-yet@~1.1.2: arg@^4.1.0: version "4.1.3" - resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== argparse@^1.0.7: version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== astral-regex@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async@^2.6.2: version "2.6.4" - resolved "https://registry.npmjs.org/async/-/async-2.6.4.tgz" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== dependencies: lodash "^4.17.14" -async@^3.2.3: - version "3.2.5" - resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== - -async@^3.2.4: - version "3.2.5" - resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== +async@^3.2.3, async@^3.2.4: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== axios@1.6.8: version "1.6.8" - resolved "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== dependencies: follow-redirects "^1.15.6" @@ -1217,7 +1197,7 @@ axios@1.6.8: babel-jest@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== dependencies: "@jest/transform" "^29.7.0" @@ -1230,7 +1210,7 @@ babel-jest@^29.7.0: babel-plugin-istanbul@^6.1.1: version "6.1.1" - resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -1241,7 +1221,7 @@ babel-plugin-istanbul@^6.1.1: babel-plugin-jest-hoist@^29.6.3: version "29.6.3" - resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" @@ -1250,26 +1230,29 @@ babel-plugin-jest-hoist@^29.6.3: "@types/babel__traverse" "^7.0.6" babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" + integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" babel-preset-jest@^29.6.3: version "29.6.3" - resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: babel-plugin-jest-hoist "^29.6.3" @@ -1277,34 +1260,34 @@ babel-preset-jest@^29.6.3: balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-js@^1.3.1: version "1.5.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== basic-auth@~2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== dependencies: safe-buffer "5.1.2" big-integer@^1.6.17: version "1.6.52" - resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== binary-extensions@^2.0.0: version "2.3.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== binary@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz" + resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" integrity sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg== dependencies: buffers "~0.1.1" @@ -1312,19 +1295,19 @@ binary@~0.3.0: bindings@^1.3.1: version "1.5.0" - resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== dependencies: file-uri-to-path "1.0.0" bintrees@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.2.tgz#49f896d6e858a4a499df85c38fb399b9aff840f8" integrity sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw== bl@^1.0.0: version "1.2.3" - resolved "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== dependencies: readable-stream "^2.3.5" @@ -1332,7 +1315,7 @@ bl@^1.0.0: bl@^2.2.0: version "2.2.1" - resolved "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz" + resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5" integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g== dependencies: readable-stream "^2.3.5" @@ -1340,7 +1323,7 @@ bl@^2.2.0: bl@^4.0.3: version "4.1.0" - resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== dependencies: buffer "^5.5.0" @@ -1349,13 +1332,13 @@ bl@^4.0.3: bluebird@~3.4.1: version "3.4.7" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA== -body-parser@^1.20.2, body-parser@1.20.2: - version "1.20.2" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== +body-parser@1.20.3, body-parser@^1.20.2: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -1365,14 +1348,14 @@ body-parser@^1.20.2, body-parser@1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -1380,43 +1363,43 @@ brace-expansion@^1.1.7: brace-expansion@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" -browserslist@^4.22.2, "browserslist@>= 4.21.0": - version "4.23.0" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== +browserslist@^4.23.1: + version "4.23.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" bser@2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== dependencies: node-int64 "^0.4.0" buffer-alloc-unsafe@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== buffer-alloc@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== dependencies: buffer-alloc-unsafe "^1.1.0" @@ -1424,27 +1407,27 @@ buffer-alloc@^1.2.0: buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.5: version "0.2.13" - resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== buffer-fill@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== buffer-from@^1.0.0: version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer-indexof-polyfill@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz#d2732135c5999c64b277fcf9b1abe3498254729c" integrity sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A== buffer@^5.5.0: version "5.7.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: base64-js "^1.3.1" @@ -1452,19 +1435,19 @@ buffer@^5.5.0: buffermaker@~1.2.0: version "1.2.1" - resolved "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/buffermaker/-/buffermaker-1.2.1.tgz#0631f92b891a84b750f1036491ac857c734429f4" integrity sha512-IdnyU2jDHU65U63JuVQNTHiWjPRH0CS3aYd/WPaEwyX84rFdukhOduAVb1jwUScmb5X0JWPw8NZOrhoLMiyAHQ== dependencies: long "1.1.2" buffers@~0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" integrity sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ== bufrw@^1.2.1: version "1.4.0" - resolved "https://registry.npmjs.org/bufrw/-/bufrw-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/bufrw/-/bufrw-1.4.0.tgz#58a294ca0bd9ebc880be83001d749706fc996499" integrity sha512-sWm8iPbqvL9+5SiYxXH73UOkyEbGQg7kyHQmReF89WJHQJw2eV4P/yZ0E+b71cczJ4pPobVhXxgQcmfSTgGHxQ== dependencies: ansi-color "^0.2.1" @@ -1474,18 +1457,18 @@ bufrw@^1.2.1: bytes@3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== bytes@3.1.2: version "3.1.2" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== cacache@^18.0.0: - version "18.0.3" - resolved "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz" - integrity sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg== + version "18.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.4.tgz#4601d7578dadb59c66044e157d02a3314682d6a5" + integrity sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ== dependencies: "@npmcli/fs" "^3.1.0" fs-minipass "^3.0.0" @@ -1502,7 +1485,7 @@ cacache@^18.0.0: call-bind@^1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: es-define-property "^1.0.0" @@ -1513,27 +1496,27 @@ call-bind@^1.0.7: callsites@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== camelcase@^5.3.1: version "5.3.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== camelcase@^6.2.0: version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001587: - version "1.0.30001620" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz" - integrity sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew== +caniuse-lite@^1.0.30001646: + version "1.0.30001663" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz#1529a723505e429fdfd49532e9fc42273ba7fed7" + integrity sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA== cfb@^1.1.3, cfb@~1.2.1: version "1.2.2" - resolved "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz" + resolved "https://registry.yarnpkg.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44" integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA== dependencies: adler-32 "~1.3.0" @@ -1541,14 +1524,14 @@ cfb@^1.1.3, cfb@~1.2.1: chainsaw@~0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" integrity sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ== dependencies: traverse ">=0.3.0 <0.4" chalk@^2.4.2: version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" @@ -1557,7 +1540,7 @@ chalk@^2.4.2: chalk@^4.0.0: version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -1565,12 +1548,12 @@ chalk@^4.0.0: char-regex@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== chokidar@^3.5.1: version "3.6.0" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" @@ -1585,32 +1568,32 @@ chokidar@^3.5.1: chownr@^1.0.1: version "1.1.4" - resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== chownr@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== ci-info@^3.2.0: version "3.9.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: - version "1.3.1" - resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz" - integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== + version "1.4.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" + integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== clean-stack@^2.0.0: version "2.2.0" - resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== cliui@^8.0.1: version "8.0.1" - resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== dependencies: string-width "^4.2.0" @@ -1619,68 +1602,61 @@ cliui@^8.0.1: clone@2.x: version "2.1.2" - resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== cluster-key-slot@^1.1.0: version "1.1.2" - resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== co@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== codepage@~1.15.0: version "1.15.0" - resolved "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz" + resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab" integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA== collect-v8-coverage@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^1.9.3: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + color-string@^1.6.0: version "1.9.1" - resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== dependencies: color-name "^1.0.0" @@ -1688,7 +1664,7 @@ color-string@^1.6.0: color@^3.1.3: version "3.2.1" - resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== dependencies: color-convert "^1.9.3" @@ -1696,7 +1672,7 @@ color@^3.1.3: colorspace@1.1.x: version "1.1.4" - resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== dependencies: color "^3.1.3" @@ -1704,14 +1680,14 @@ colorspace@1.1.x: combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" compress-commons@^4.1.2: version "4.1.2" - resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.2.tgz#6542e59cb63e1f46a8b21b0e06f9a32e4c8b06df" integrity sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg== dependencies: buffer-crc32 "^0.2.13" @@ -1721,14 +1697,14 @@ compress-commons@^4.1.2: compressible@~2.0.16: version "2.0.18" - resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== dependencies: mime-db ">= 1.43.0 < 2" compression@1.7.4: version "1.7.4" - resolved "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== dependencies: accepts "~1.3.5" @@ -1741,54 +1717,54 @@ compression@1.7.4: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== content-disposition@0.5.4: version "0.5.4" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== dependencies: safe-buffer "5.2.1" content-type@~1.0.4, content-type@~1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== convert-source-map@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== cookie@0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== core-util-is@~1.0.0: version "1.0.3" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== crc-32@^1.2.0, crc-32@~1.2.0, crc-32@~1.2.1: version "1.2.2" - resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== crc32-stream@^4.0.2: version "4.0.3" - resolved "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.3.tgz#85dd677eb78fa7cad1ba17cc506a597d41fc6f33" integrity sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw== dependencies: crc-32 "^1.2.0" @@ -1796,7 +1772,7 @@ crc32-stream@^4.0.2: create-jest@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== dependencies: "@jest/types" "^29.6.3" @@ -1809,12 +1785,12 @@ create-jest@^29.7.0: create-require@^1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" @@ -1822,89 +1798,54 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: which "^2.0.1" dayjs@^1.8.34: - version "1.11.11" - resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz" - integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== -debug@^2.1.3, debug@2.6.9: +debug@2.6.9, debug@^2.1.3: version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^4.0.1: - version "4.3.5" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4, debug@^4.3.6: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: - ms "2.1.2" - -debug@^4.1.0: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@^4.1.1: - version "4.3.5" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== - dependencies: - ms "2.1.2" - -debug@^4.3.1: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@^4.3.4: - version "4.3.5" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== - dependencies: - ms "2.1.2" - -debug@4: - version "4.3.5" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== - dependencies: - ms "2.1.2" + ms "^2.1.3" decompress-response@^3.3.0: version "3.3.0" - resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== dependencies: mimic-response "^1.0.0" dedent@^1.0.0: version "1.5.3" - resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deep-extend@^0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: version "4.3.1" - resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== define-data-property@^1.1.4: version "1.1.4" - resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: es-define-property "^1.0.0" @@ -1913,132 +1854,137 @@ define-data-property@^1.1.4: delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== delegates@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== denque@^1.3.0: version "1.5.1" - resolved "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== denque@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== -depd@~2.0.0, depd@2.0.0: +depd@2.0.0, depd@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== destroy@1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== detect-libc@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== detect-newline@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== diff-sequences@^29.6.3: version "29.6.3" - resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== diff@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== doctrine@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== dependencies: esutils "^2.0.2" duplexer2@~0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" integrity sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA== dependencies: readable-stream "^2.0.2" dynamic-dedupe@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz" + resolved "https://registry.yarnpkg.com/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz#06e44c223f5e4e94d78ef9db23a6515ce2f962a1" integrity sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ== dependencies: xtend "^4.0.0" eastasianwidth@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== ee-first@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.668: - version "1.4.772" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.772.tgz" - integrity sha512-jFfEbxR/abTTJA3ci+2ok1NTuOBBtB4jH+UT6PUmRN+DY3WSD4FFRsgoVQ+QNIJ0T7wrXwzsWCI2WKC46b++2A== +electron-to-chromium@^1.5.4: + version "1.5.27" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz#5203ce5d6054857d84ba84d3681cbe59132ade78" + integrity sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw== emittery@^0.13.1: version "0.13.1" - resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== emoji-regex@^9.2.2: version "9.2.2" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== enabled@2.0.x: version "2.0.0" - resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== encodeurl@~1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + encoding@^0.1.13: version "0.1.13" - resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== dependencies: iconv-lite "^0.6.2" end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" - resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" enquirer@^2.3.5: version "2.4.1" - resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== dependencies: ansi-colors "^4.1.1" @@ -2046,64 +1992,71 @@ enquirer@^2.3.5: env-paths@^2.2.0: version "2.2.1" - resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== err-code@^2.0.2: version "2.0.3" - resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== error-ex@^1.3.1: version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -error@^7.0.0, error@7.0.2: +error@7.0.2: version "7.0.2" - resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz" + resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" integrity sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw== dependencies: string-template "~0.2.1" xtend "~4.0.0" +error@^7.0.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894" + integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA== + dependencies: + string-template "~0.2.1" + es-define-property@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== dependencies: get-intrinsic "^1.2.4" es-errors@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== escalade@^3.1.1, escalade@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== escodegen@^1.8.1: version "1.14.3" - resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== dependencies: esprima "^4.0.1" @@ -2115,7 +2068,7 @@ escodegen@^1.8.1: eslint-scope@^5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: esrecurse "^4.3.0" @@ -2123,29 +2076,24 @@ eslint-scope@^5.1.1: eslint-utils@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^1.3.0: +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== eslint-visitor-keys@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== eslint@7.16.0: version "7.16.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.16.0.tgz#a761605bf9a7b32d24bb7cde59aeb0fd76f06092" integrity sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw== dependencies: "@babel/code-frame" "^7.0.0" @@ -2188,75 +2136,65 @@ eslint@7.16.0: espree@^7.3.0, espree@^7.3.1: version "7.3.1" - resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== dependencies: acorn "^7.4.0" acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - esprima@1.2.2: version "1.2.2" - resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.2.tgz#76a0fd66fcfe154fd292667dc264019750b1657b" integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A== +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + esquery@^1.2.0: - version "1.5.0" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: estraverse "^5.2.0" estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== etag@~1.8.1: version "1.8.1" - resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== eventemitter3@^4.0.0: version "4.0.7" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -exceljs@4.4.0: +exceljs@^4.4.0: version "4.4.0" - resolved "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz" + resolved "https://registry.yarnpkg.com/exceljs/-/exceljs-4.4.0.tgz#cfb1cb8dcc82c760a9fc9faa9e52dadab66b0156" integrity sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg== dependencies: archiver "^5.0.0" @@ -2271,7 +2209,7 @@ exceljs@4.4.0: execa@^5.0.0: version "5.1.1" - resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" @@ -2286,17 +2224,17 @@ execa@^5.0.0: exit@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== expand-template@^2.0.3: version "2.0.3" - resolved "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== expect@^29.0.0, expect@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== dependencies: "@jest/expect-utils" "^29.7.0" @@ -2307,40 +2245,40 @@ expect@^29.0.0, expect@^29.7.0: exponential-backoff@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== express@^4.19.2: - version "4.19.2" - resolved "https://registry.npmjs.org/express/-/express-4.19.2.tgz" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.2" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.10" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -2349,7 +2287,7 @@ express@^4.19.2: fast-csv@^4.3.1: version "4.3.6" - resolved "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz" + resolved "https://registry.yarnpkg.com/fast-csv/-/fast-csv-4.3.6.tgz#70349bdd8fe4d66b1130d8c91820b64a21bc4a63" integrity sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw== dependencies: "@fast-csv/format" "4.3.5" @@ -2357,57 +2295,62 @@ fast-csv@^4.3.1: fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + fb-watchman@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== dependencies: bser "2.1.1" fecha@^4.2.0: version "4.2.3" - resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== file-entry-cache@^6.0.0: version "6.0.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: flat-cache "^3.0.4" file-uri-to-path@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -2416,7 +2359,7 @@ finalhandler@1.2.0: find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: locate-path "^5.0.0" @@ -2424,7 +2367,7 @@ find-up@^4.0.0, find-up@^4.1.0: flat-cache@^3.0.4: version "3.2.0" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: flatted "^3.2.9" @@ -2433,30 +2376,30 @@ flat-cache@^3.0.4: flatted@^3.2.9: version "3.3.1" - resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== fn.name@1.x.x: version "1.1.0" - resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== follow-redirects@^1.0.0, follow-redirects@^1.15.6: - version "1.15.6" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== foreground-child@^3.1.0: - version "3.2.0" - resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz" - integrity sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA== + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" form-data@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" @@ -2465,46 +2408,51 @@ form-data@^4.0.0: forwarded@0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== frac@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b" integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA== fresh@0.5.2: version "0.5.2" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== fs-constants@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== fs-minipass@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== dependencies: minipass "^3.0.0" fs-minipass@^3.0.0: version "3.0.3" - resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-3.0.3.tgz#79a85981c4dc120065e96f62086bf6f9dc26cc54" integrity sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw== dependencies: minipass "^7.0.3" fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + fstream@^1.0.12: version "1.0.12" - resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== dependencies: graceful-fs "^4.1.2" @@ -2514,17 +2462,17 @@ fstream@^1.0.12: function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== functional-red-black-tree@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== gauge@~2.7.3: version "2.7.4" - resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" integrity sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg== dependencies: aproba "^1.0.3" @@ -2538,17 +2486,17 @@ gauge@~2.7.3: gensync@^1.0.0-beta.2: version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: version "1.2.4" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: es-errors "^1.3.0" @@ -2559,64 +2507,41 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: get-package-type@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== get-stream@^6.0.0: version "6.0.1" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== github-from-package@0.0.0: version "0.0.0" - resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== glob-parent@^5.0.0, glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" glob@^10.2.2, glob@^10.3.10: - version "10.4.1" - resolved "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz" - integrity sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw== + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== dependencies: foreground-child "^3.1.0" jackspeak "^3.1.2" minimatch "^9.0.4" minipass "^7.1.2" + package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.1.4: +glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.2.3: - version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -2628,80 +2553,80 @@ glob@^7.2.3: globals@^11.1.0: version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^12.1.0: version "12.4.0" - resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== dependencies: type-fest "^0.8.1" gopd@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== dependencies: get-intrinsic "^1.1.3" graceful-fs@^4.1.2, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-property-descriptors@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: es-define-property "^1.0.0" has-proto@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== has-symbols@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== has-unicode@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== hash-sum@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a" integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg== -hasown@^2.0.0: +hasown@^2.0.0, hasown@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" helmet@7.1.0: version "7.1.0" - resolved "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-7.1.0.tgz#287279e00f8a3763d5dccbaf1e5ee39b8c3784ca" integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== hexer@^1.5.0: version "1.5.0" - resolved "https://registry.npmjs.org/hexer/-/hexer-1.5.0.tgz" + resolved "https://registry.yarnpkg.com/hexer/-/hexer-1.5.0.tgz#b86ce808598e8a9d1892c571f3cedd86fc9f0653" integrity sha512-dyrPC8KzBzUJ19QTIo1gXNqIISRXQ0NwteW6OeQHRN4ZuZeHkdODfj0zHBdOlHbRY8GqbqK57C9oWSvQZizFsg== dependencies: ansi-color "^0.2.1" @@ -2711,17 +2636,17 @@ hexer@^1.5.0: html-escaper@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== http-cache-semantics@^4.1.1: version "4.1.1" - resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== http-errors@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: depd "2.0.0" @@ -2732,27 +2657,27 @@ http-errors@2.0.0: http-proxy-agent@^7.0.0: version "7.0.2" - resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== dependencies: agent-base "^7.1.0" debug "^4.3.4" http-proxy-middleware@*, http-proxy-middleware@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz" - integrity sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw== + version "3.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-3.0.2.tgz#c834aad7cac47a229205399ab64a102e9bbed820" + integrity sha512-fBLFpmvDzlxdckwZRjM0wWtwDZ4KBtQ8NFqhrFKoEtK4myzuiumBuNTxD+F4cVbXfOZljIbrynmvByofDzT7Ag== dependencies: - "@types/http-proxy" "^1.17.10" - debug "^4.3.4" + "@types/http-proxy" "^1.17.15" + debug "^4.3.6" http-proxy "^1.18.1" - is-glob "^4.0.1" - is-plain-obj "^3.0.0" - micromatch "^4.0.5" + is-glob "^4.0.3" + is-plain-object "^5.0.0" + micromatch "^4.0.8" http-proxy@^1.18.1: version "1.18.1" - resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== dependencies: eventemitter3 "^4.0.0" @@ -2760,94 +2685,94 @@ http-proxy@^1.18.1: requires-port "^1.0.0" https-proxy-agent@^7.0.1: - version "7.0.4" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz" - integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg== + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== dependencies: agent-base "^7.0.2" debug "4" human-signals@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -iconv-lite@^0.6.2: - version "0.6.3" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - iconv-lite@0.4.24: version "0.4.24" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + ieee754@^1.1.13: version "1.2.1" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore@^4.0.6: version "4.0.6" - resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== immediate@~3.0.5: version "3.0.6" - resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== indent-string@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" -inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3, inherits@2, inherits@2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3: version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== ini@~1.3.0: version "1.3.8" - resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== ioredis@^5.4.1: version "5.4.1" - resolved "https://registry.npmjs.org/ioredis/-/ioredis-5.4.1.tgz" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.4.1.tgz#1c56b70b759f01465913887375ed809134296f40" integrity sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA== dependencies: "@ioredis/commands" "^1.1.1" @@ -2862,7 +2787,7 @@ ioredis@^5.4.1: ip-address@^9.0.5: version "9.0.5" - resolved "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== dependencies: jsbn "1.1.0" @@ -2870,105 +2795,105 @@ ip-address@^9.0.5: ipaddr.js@1.9.1: version "1.9.1" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-arrayish@^0.3.1: version "0.3.2" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" is-core-module@^2.13.0: - version "2.13.1" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== dependencies: - hasown "^2.0.0" + hasown "^2.0.2" is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-generator-fn@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" is-lambda@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== is-number@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-plain-obj@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz" - integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== is-stream@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== isarray@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isexe@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.2" - resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== istanbul-lib-instrument@^5.0.4: version "5.2.1" - resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== dependencies: "@babel/core" "^7.12.3" @@ -2978,9 +2903,9 @@ istanbul-lib-instrument@^5.0.4: semver "^6.3.0" istanbul-lib-instrument@^6.0.0: - version "6.0.2" - resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz" - integrity sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw== + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== dependencies: "@babel/core" "^7.23.9" "@babel/parser" "^7.23.9" @@ -2990,7 +2915,7 @@ istanbul-lib-instrument@^6.0.0: istanbul-lib-report@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: istanbul-lib-coverage "^3.0.0" @@ -2999,7 +2924,7 @@ istanbul-lib-report@^3.0.0: istanbul-lib-source-maps@^4.0.0: version "4.0.1" - resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" @@ -3008,16 +2933,16 @@ istanbul-lib-source-maps@^4.0.0: istanbul-reports@^3.1.3: version "3.1.7" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" jackspeak@^3.1.2: - version "3.4.0" - resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz" - integrity sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw== + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -3025,7 +2950,7 @@ jackspeak@^3.1.2: jaeger-client@^3.19.0: version "3.19.0" - resolved "https://registry.npmjs.org/jaeger-client/-/jaeger-client-3.19.0.tgz" + resolved "https://registry.yarnpkg.com/jaeger-client/-/jaeger-client-3.19.0.tgz#9b5bd818ebd24e818616ee0f5cffe1722a53ae6e" integrity sha512-M0c7cKHmdyEUtjemnJyx/y9uX16XHocL46yQvyqDlPdvAcwPDbHrIbKjQdBqtiE4apQ/9dmr+ZLJYYPGnurgpw== dependencies: node-int64 "^0.4.0" @@ -3036,7 +2961,7 @@ jaeger-client@^3.19.0: jest-changed-files@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: execa "^5.0.0" @@ -3045,7 +2970,7 @@ jest-changed-files@^29.7.0: jest-circus@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== dependencies: "@jest/environment" "^29.7.0" @@ -3071,7 +2996,7 @@ jest-circus@^29.7.0: jest-cli@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: "@jest/core" "^29.7.0" @@ -3088,7 +3013,7 @@ jest-cli@^29.7.0: jest-config@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== dependencies: "@babel/core" "^7.11.6" @@ -3116,7 +3041,7 @@ jest-config@^29.7.0: jest-diff@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== dependencies: chalk "^4.0.0" @@ -3126,14 +3051,14 @@ jest-diff@^29.7.0: jest-docblock@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== dependencies: detect-newline "^3.0.0" jest-each@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: "@jest/types" "^29.6.3" @@ -3144,7 +3069,7 @@ jest-each@^29.7.0: jest-environment-node@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== dependencies: "@jest/environment" "^29.7.0" @@ -3156,12 +3081,12 @@ jest-environment-node@^29.7.0: jest-get-type@^29.6.3: version "29.6.3" - resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== jest-haste-map@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: "@jest/types" "^29.6.3" @@ -3180,7 +3105,7 @@ jest-haste-map@^29.7.0: jest-leak-detector@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: jest-get-type "^29.6.3" @@ -3188,7 +3113,7 @@ jest-leak-detector@^29.7.0: jest-matcher-utils@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== dependencies: chalk "^4.0.0" @@ -3198,7 +3123,7 @@ jest-matcher-utils@^29.7.0: jest-message-util@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== dependencies: "@babel/code-frame" "^7.12.13" @@ -3213,7 +3138,7 @@ jest-message-util@^29.7.0: jest-mock@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== dependencies: "@jest/types" "^29.6.3" @@ -3222,25 +3147,25 @@ jest-mock@^29.7.0: jest-pnp-resolver@^1.2.2: version "1.2.3" - resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== jest-regex-util@^29.6.3: version "29.6.3" - resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== jest-resolve-dependencies@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: jest-regex-util "^29.6.3" jest-snapshot "^29.7.0" -jest-resolve@*, jest-resolve@^29.7.0: +jest-resolve@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: chalk "^4.0.0" @@ -3255,7 +3180,7 @@ jest-resolve@*, jest-resolve@^29.7.0: jest-runner@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== dependencies: "@jest/console" "^29.7.0" @@ -3282,7 +3207,7 @@ jest-runner@^29.7.0: jest-runtime@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== dependencies: "@jest/environment" "^29.7.0" @@ -3310,7 +3235,7 @@ jest-runtime@^29.7.0: jest-snapshot@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: "@babel/core" "^7.11.6" @@ -3336,7 +3261,7 @@ jest-snapshot@^29.7.0: jest-util@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: "@jest/types" "^29.6.3" @@ -3348,7 +3273,7 @@ jest-util@^29.7.0: jest-validate@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== dependencies: "@jest/types" "^29.6.3" @@ -3360,7 +3285,7 @@ jest-validate@^29.7.0: jest-watcher@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: "@jest/test-result" "^29.7.0" @@ -3374,7 +3299,7 @@ jest-watcher@^29.7.0: jest-worker@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: "@types/node" "*" @@ -3384,7 +3309,7 @@ jest-worker@^29.7.0: jest@29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: "@jest/core" "^29.7.0" @@ -3394,12 +3319,12 @@ jest@29.7.0: js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: version "3.14.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" @@ -3407,47 +3332,47 @@ js-yaml@^3.13.1: jsbn@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== json-buffer@3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== json-parse-even-better-errors@^2.3.0: version "2.3.1" - resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema-traverse@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== json5@^2.2.3: version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== jsonpath@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/jsonpath/-/jsonpath-1.1.1.tgz#0ca1ed8fb65bb3309248cc9d5466d12d5b0b9901" integrity sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w== dependencies: esprima "1.2.2" @@ -3456,7 +3381,7 @@ jsonpath@1.1.1: jszip@^3.10.1, jszip@^3.2.2: version "3.10.1" - resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== dependencies: lie "~3.3.0" @@ -3466,7 +3391,7 @@ jszip@^3.10.1, jszip@^3.2.2: kafka-node@5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/kafka-node/-/kafka-node-5.0.0.tgz#4b6f65cc1d77ebe565859dfb8f9575ed15d543c0" integrity sha512-dD2ga5gLcQhsq1yNoQdy1MU4x4z7YnXM5bcG9SdQuiNr5KKuAmXixH1Mggwdah5o7EfholFbcNDPSVA6BIfaug== dependencies: async "^2.6.2" @@ -3487,36 +3412,36 @@ kafka-node@5.0.0: keyv@^4.5.3: version "4.5.4" - resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" kleur@^3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== kuler@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== lazystream@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== dependencies: readable-stream "^2.0.5" leven@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== levn@^0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" @@ -3524,7 +3449,7 @@ levn@^0.4.1: levn@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== dependencies: prelude-ls "~1.1.2" @@ -3532,112 +3457,112 @@ levn@~0.3.0: lie@~3.3.0: version "3.3.0" - resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== dependencies: immediate "~3.0.5" lines-and-columns@^1.1.6: version "1.2.4" - resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== listenercount@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" integrity sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ== locate-path@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: p-locate "^4.1.0" lodash.defaults@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== lodash.difference@^4.5.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== lodash.escaperegexp@^4.1.2: version "4.1.2" - resolved "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" integrity sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw== lodash.flatten@^4.4.0: version "4.4.0" - resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== lodash.groupby@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" integrity sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw== lodash.isarguments@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== lodash.isboolean@^3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== lodash.isequal@^4.5.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== lodash.isfunction@^3.0.9: version "3.0.9" - resolved "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== lodash.isnil@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz#49e28cd559013458c814c5479d3c663a21bfaa6c" integrity sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng== lodash.isplainobject@^4.0.6: version "4.0.6" - resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== lodash.isundefined@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz#23ef3d9535565203a66cefd5b830f848911afb48" integrity sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA== lodash.truncate@^4.4.2: version "4.4.2" - resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== lodash.union@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== lodash.uniq@^4.5.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@4.17.21: +lodash@4.17.21, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4: version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -logform@^2.3.2, logform@^2.4.0: - version "2.6.0" - resolved "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz" - integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ== +logform@^2.4.0, logform@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.1.tgz#71403a7d8cae04b2b734147963236205db9b3df0" + integrity sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA== dependencies: "@colors/colors" "1.6.0" "@types/triple-beam" "^1.3.2" @@ -3646,43 +3571,43 @@ logform@^2.3.2, logform@^2.4.0: safe-stable-stringify "^2.3.1" triple-beam "^1.3.0" -long@^2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/long/-/long-2.4.0.tgz" - integrity sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ== - long@1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/long/-/long-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/long/-/long-1.1.2.tgz#eaef5951ca7551d96926b82da242db9d6b28fb53" integrity sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q== +long@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/long/-/long-2.4.0.tgz#9fa180bb1d9500cdc29c4156766a1995e1f4524f" + integrity sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ== + lru-cache@^10.0.1, lru-cache@^10.2.0: - version "10.2.2" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz" - integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lru-cache@^5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: yallist "^3.0.2" make-dir@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== dependencies: semver "^7.5.3" make-error@^1.1.1: version "1.3.6" - resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== make-fetch-happen@^13.0.0: version "13.0.1" - resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz#273ba2f78f45e1f3a6dca91cede87d9fa4821e36" integrity sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA== dependencies: "@npmcli/agent" "^2.0.0" @@ -3700,102 +3625,107 @@ make-fetch-happen@^13.0.0: makeerror@1.0.12: version "1.0.12" - resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: tmpl "1.0.5" media-typer@0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== methods@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^4.0.4, micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.4, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" -"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: +mime-db@1.52.0: version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== +"mime-db@>= 1.43.0 < 2": + version "1.53.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" + integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== + mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" mime@1.6.0: version "1.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== mimic-response@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" minimatch@^5.1.0: version "5.1.6" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== dependencies: brace-expansion "^2.0.1" minimatch@^9.0.4: - version "9.0.4" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz" - integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.6: version "1.2.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minipass-collect@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-2.0.1.tgz#1621bc77e12258a12c60d34e2276ec5c20680863" integrity sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw== dependencies: minipass "^7.0.3" minipass-fetch@^3.0.0: version "3.0.5" - resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-3.0.5.tgz#f0f97e40580affc4a35cc4a1349f05ae36cb1e4c" integrity sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg== dependencies: minipass "^7.0.3" @@ -3806,70 +3736,65 @@ minipass-fetch@^3.0.0: minipass-flush@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== dependencies: minipass "^3.0.0" minipass-pipeline@^1.2.4: version "1.2.4" - resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== dependencies: minipass "^3.0.0" minipass-sized@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== dependencies: minipass "^3.0.0" minipass@^3.0.0: version "3.3.6" - resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== dependencies: yallist "^4.0.0" -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== - minipass@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" - resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== dependencies: minipass "^3.0.0" yallist "^4.0.0" -mkdirp@^0.5.1, "mkdirp@>=0.5 0": +"mkdirp@>=0.5 0", mkdirp@^0.5.1: version "0.5.6" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: minimist "^1.2.6" -mkdirp@^1.0.3: +mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== morgan@1.10.0: version "1.10.0" - resolved "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== dependencies: basic-auth "~2.0.1" @@ -3878,68 +3803,58 @@ morgan@1.10.0: on-finished "~2.3.0" on-headers "~1.0.2" -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - ms@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3: +ms@2.1.3, ms@^2.1.1, ms@^2.1.3: version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== nan@^2.14.1: - version "2.19.0" - resolved "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz" - integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== + version "2.20.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" + integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== napi-build-utils@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@^0.6.3, negotiator@0.6.3: +negotiator@0.6.3, negotiator@^0.6.3: version "0.6.3" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== nested-error-stacks@^2.0.0: version "2.1.1" - resolved "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== node-abi@^2.7.0: version "2.30.1" - resolved "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.30.1.tgz#c437d4b1fe0e285aaf290d45b45d4d7afedac4cf" integrity sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w== dependencies: semver "^5.4.1" node-cache@5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d" integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== dependencies: clone "2.x" node-gyp@10.0.1: version "10.0.1" - resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.0.1.tgz#205514fc19e5830fa991e4a689f9e81af377a966" integrity sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg== dependencies: env-paths "^2.2.0" @@ -3955,41 +3870,41 @@ node-gyp@10.0.1: node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== noop-logger@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz" + resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" integrity sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ== nopt@^7.0.0: version "7.2.1" - resolved "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.1.tgz#1cac0eab9b8e97c9093338446eddd40b2c8ca1e7" integrity sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w== dependencies: abbrev "^2.0.0" normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== npm-run-path@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" npmlog@^4.0.1: version "4.1.2" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" @@ -3999,77 +3914,77 @@ npmlog@^4.0.1: number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== object-assign@^4.1.0: version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-inspect@^1.13.1: - version "1.13.1" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== obuf@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" - integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== - dependencies: - ee-first "1.1.1" - on-finished@2.4.1: version "2.4.1" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== dependencies: ee-first "1.1.1" +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + on-headers@~1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" one-time@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== dependencies: fn.name "1.x.x" onetime@^5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" opentracing@^0.14.4, opentracing@^0.14.7, opentracing@~0.14.3: version "0.14.7" - resolved "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz" + resolved "https://registry.yarnpkg.com/opentracing/-/opentracing-0.14.7.tgz#25d472bd0296dc0b64d7b94cbc995219031428f5" integrity sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q== optional@^0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/optional/-/optional-0.1.4.tgz#cdb1a9bedc737d2025f690ceeb50e049444fd5b3" integrity sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw== optionator@^0.8.1: version "0.8.3" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" @@ -4081,7 +3996,7 @@ optionator@^0.8.1: optionator@^0.9.1: version "0.9.4" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" @@ -4093,57 +4008,62 @@ optionator@^0.9.1: os-homedir@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== p-limit@^2.2.0: version "2.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" p-limit@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" p-locate@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== dependencies: p-limit "^2.2.0" p-map@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== dependencies: aggregate-error "^3.0.0" p-try@^2.0.0: version "2.2.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + pako@~1.0.2: version "1.0.11" - resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== parent-module@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" parse-json@^5.2.0: version "5.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" @@ -4153,75 +4073,75 @@ parse-json@^5.2.0: parseurl@~1.3.3: version "1.3.3" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-scurry@^1.11.1: version "1.11.1" - resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== pg-cloudflare@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98" integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== pg-connection-string@^2.6.4: - version "2.6.4" - resolved "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz" - integrity sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA== + version "2.7.0" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.7.0.tgz#f1d3489e427c62ece022dba98d5262efcb168b37" + integrity sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA== pg-int8@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== pg-numeric@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a" integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== pg-pool@^3.6.2: - version "3.6.2" - resolved "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz" - integrity sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg== + version "3.7.0" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.7.0.tgz#d4d3c7ad640f8c6a2245adc369bafde4ebb8cbec" + integrity sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g== pg-protocol@*, pg-protocol@^1.6.1: - version "1.6.1" - resolved "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz" - integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg== + version "1.7.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.7.0.tgz#ec037c87c20515372692edac8b63cf4405448a93" + integrity sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ== pg-types@^2.1.0: version "2.2.0" - resolved "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== dependencies: pg-int8 "1.0.1" @@ -4232,7 +4152,7 @@ pg-types@^2.1.0: pg-types@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-4.0.2.tgz#399209a57c326f162461faa870145bb0f918b76d" integrity sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng== dependencies: pg-int8 "1.0.1" @@ -4243,9 +4163,9 @@ pg-types@^4.0.1: postgres-interval "^3.0.0" postgres-range "^1.1.1" -pg@>=8.0, pg@8.12.0: +pg@8.12.0: version "8.12.0" - resolved "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.12.0.tgz#9341724db571022490b657908f65aee8db91df79" integrity sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ== dependencies: pg-connection-string "^2.6.4" @@ -4258,85 +4178,85 @@ pg@>=8.0, pg@8.12.0: pgpass@1.x: version "1.0.5" - resolved "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== dependencies: split2 "^4.1.0" picocolors@^1.0.0, picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pirates@^4.0.4: version "4.0.6" - resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== pkg-dir@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" postgres-array@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== postgres-array@~3.0.1: version "3.0.2" - resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-3.0.2.tgz#68d6182cb0f7f152a7e60dc6a6889ed74b0a5f98" integrity sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog== postgres-bytea@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== postgres-bytea@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-3.0.0.tgz#9048dc461ac7ba70a6a42d109221619ecd1cb089" integrity sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw== dependencies: obuf "~1.1.2" postgres-date@~1.0.4: version "1.0.7" - resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== postgres-date@~2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-2.1.0.tgz#b85d3c1fb6fb3c6c8db1e9942a13a3bf625189d0" integrity sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA== postgres-interval@^1.1.0: version "1.2.0" - resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== dependencies: xtend "^4.0.0" postgres-interval@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-3.0.0.tgz#baf7a8b3ebab19b7f38f07566c7aab0962f0c86a" integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw== postgres-range@^1.1.1: version "1.1.4" - resolved "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863" integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== prebuild-install@5.3.0: version "5.3.0" - resolved "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.0.tgz#58b4d8344e03590990931ee088dd5401b03004c8" integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg== dependencies: detect-libc "^1.0.3" @@ -4358,17 +4278,17 @@ prebuild-install@5.3.0: prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== dependencies: "@jest/schemas" "^29.6.3" @@ -4377,39 +4297,39 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: proc-log@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== proc-log@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-4.2.0.tgz#b6f461e4026e75fdfe228b265e9f7a00779d7034" integrity sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA== process-nextick-args@~2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== process@^0.10.0: version "0.10.1" - resolved "https://registry.npmjs.org/process/-/process-0.10.1.tgz" + resolved "https://registry.yarnpkg.com/process/-/process-0.10.1.tgz#842457cc51cfed72dc775afeeafb8c6034372725" integrity sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA== progress@^2.0.0: version "2.0.3" - resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== "prom-client@~11.3.0 || ^12.0.0 || ^13.0.0 || ^14.0.0": version "14.2.0" - resolved "https://registry.npmjs.org/prom-client/-/prom-client-14.2.0.tgz" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.2.0.tgz#ca94504e64156f6506574c25fb1c34df7812cf11" integrity sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA== dependencies: tdigest "^0.1.1" promise-retry@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== dependencies: err-code "^2.0.2" @@ -4417,7 +4337,7 @@ promise-retry@^2.0.1: prompts@^2.0.1: version "2.4.2" - resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: kleur "^3.0.3" @@ -4425,12 +4345,12 @@ prompts@^2.0.1: property-expr@^2.0.5: version "2.0.6" - resolved "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== proxy-addr@~2.0.7: version "2.0.7" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: forwarded "0.2.0" @@ -4438,12 +4358,12 @@ proxy-addr@~2.0.7: proxy-from-env@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== pump@^1.0.0: version "1.0.3" - resolved "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== dependencies: end-of-stream "^1.1.0" @@ -4451,7 +4371,7 @@ pump@^1.0.0: pump@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== dependencies: end-of-stream "^1.1.0" @@ -4459,29 +4379,29 @@ pump@^2.0.1: punycode@^2.1.0: version "2.3.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== pure-rand@^6.0.0: version "6.1.0" - resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" range-parser@~1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== raw-body@2.5.2: version "2.5.2" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" @@ -4491,7 +4411,7 @@ raw-body@2.5.2: rc@^1.2.7: version "1.2.8" - resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" @@ -4501,12 +4421,12 @@ rc@^1.2.7: react-is@^18.0.0: version "18.3.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" @@ -4517,9 +4437,9 @@ readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0, readable-stream@^3.6.2: version "3.6.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" @@ -4528,75 +4448,75 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: readdir-glob@^1.1.2: version "1.1.3" - resolved "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584" integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== dependencies: minimatch "^5.1.0" readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" redis-errors@^1.0.0, redis-errors@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== redis-parser@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== dependencies: redis-errors "^1.0.0" regexpp@^3.1.0: version "3.2.0" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-from-string@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== requires-port@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== resolve-cwd@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== dependencies: resolve-from "^5.0.0" resolve-from@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve-from@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve.exports@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== resolve@^1.0.0, resolve@^1.20.0: version "1.22.8" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" @@ -4605,106 +4525,79 @@ resolve@^1.0.0, resolve@^1.20.0: retry@^0.10.1: version "0.10.1" - resolved "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" integrity sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ== retry@^0.12.0: version "0.12.0" - resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== -rimraf@^2.6.1: +rimraf@2, rimraf@^2.6.1: version "2.7.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: glob "^7.1.3" rimraf@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -rimraf@2: - version "2.7.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@5.1.2: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== safe-stable-stringify@^2.3.1: - version "2.4.3" - resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz" - integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sax@^1.2.4: - version "1.3.0" - resolved "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz" - integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== + version "1.4.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" + integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== saxes@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== dependencies: xmlchars "^2.2.0" semver@^5.4.1: version "5.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.3.0: +semver@^6.3.0, semver@^6.3.1: version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.2.1: - version "7.6.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" - integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== - -semver@^7.3.5: - version "7.6.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" - integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== - -semver@^7.5.3: - version "7.6.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" - integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== +semver@^7.2.1, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -semver@^7.5.4: - version "7.6.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" - integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== - -send@0.18.0: - version "0.18.0" - resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -4720,24 +4613,24 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== set-function-length@^1.2.1: version "1.2.2" - resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: define-data-property "^1.1.4" @@ -4749,29 +4642,29 @@ set-function-length@^1.2.1: setimmediate@^1.0.5, setimmediate@~1.0.4: version "1.0.5" - resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== setprototypeof@1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4: +side-channel@^1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: call-bind "^1.0.7" @@ -4781,22 +4674,22 @@ side-channel@^1.0.4: signal-exit@^3.0.0, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== signal-exit@^4.0.1: version "4.1.0" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== simple-concat@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== simple-get@^2.7.0: version "2.8.2" - resolved "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.2.tgz#5708fb0919d440657326cd5fe7d2599d07705019" integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== dependencies: decompress-response "^3.3.0" @@ -4805,24 +4698,24 @@ simple-get@^2.7.0: simple-swizzle@^0.2.2: version "0.2.2" - resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== dependencies: is-arrayish "^0.3.1" sisteransi@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== slash@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== slice-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== dependencies: ansi-styles "^4.0.0" @@ -4831,12 +4724,12 @@ slice-ansi@^4.0.0: smart-buffer@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== snappy@^6.0.1: version "6.3.5" - resolved "https://registry.npmjs.org/snappy/-/snappy-6.3.5.tgz" + resolved "https://registry.yarnpkg.com/snappy/-/snappy-6.3.5.tgz#c14b8dea8e9bc2687875b5e491d15dd900e6023c" integrity sha512-lonrUtdp1b1uDn1dbwgQbBsb5BbaiLeKq+AGwOk2No+en+VvJThwmtztwulEQsLinRF681pBqib0NUZaizKLIA== dependencies: bindings "^1.3.1" @@ -4844,103 +4737,104 @@ snappy@^6.0.1: prebuild-install "5.3.0" socks-proxy-agent@^8.0.3: - version "8.0.3" - resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz" - integrity sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A== + version "8.0.4" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz#9071dca17af95f483300316f4b063578fa0db08c" + integrity sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw== dependencies: agent-base "^7.1.1" debug "^4.3.4" - socks "^2.7.1" + socks "^2.8.3" -socks@^2.7.1: +socks@^2.8.3: version "2.8.3" - resolved "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== dependencies: ip-address "^9.0.5" smart-buffer "^4.2.0" -source-map-support@^0.5.12, source-map-support@0.5.13: +source-map-support@0.5.13: version "0.5.13" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@^0.5.12: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== split2@^4.1.0: version "4.2.0" - resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== sprintf-js@^1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== ssf@~0.11.2: version "0.11.2" - resolved "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz" + resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c" integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g== dependencies: frac "~1.1.2" ssri@^10.0.0: version "10.0.6" - resolved "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.6.tgz#a8aade2de60ba2bce8688e3fa349bad05c7dc1e5" integrity sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ== dependencies: minipass "^7.0.3" stack-trace@0.0.x: version "0.0.10" - resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== stack-utils@^2.0.3: version "2.0.6" - resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== dependencies: escape-string-regexp "^2.0.0" standard-as-callback@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== static-eval@2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42" integrity sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg== dependencies: escodegen "^1.8.1" statuses@2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -string_decoder@^1.1.1, string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - string-length@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: char-regex "^1.0.2" @@ -4948,150 +4842,125 @@ string-length@^4.0.1: string-template@~0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" integrity sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw== -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^1.0.1, "string-width@^1.0.2 || 2 || 3 || 4": +string-width@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^5.0.1: +string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: eastasianwidth "^0.2.0" emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" + safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== dependencies: ansi-regex "^2.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: ansi-regex "^6.0.1" strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-bom@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== strip-final-newline@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -strip-json-comments@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strip-json-comments@^3.1.1: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" supports-color@^8.0.0: version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== table@^6.0.4: version "6.8.2" - resolved "https://registry.npmjs.org/table/-/table-6.8.2.tgz" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.2.tgz#c5504ccf201213fa227248bdc8c5569716ac6c58" integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA== dependencies: ajv "^8.0.1" @@ -5102,7 +4971,7 @@ table@^6.0.4: tar-fs@^1.13.0: version "1.16.3" - resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== dependencies: chownr "^1.0.1" @@ -5112,7 +4981,7 @@ tar-fs@^1.13.0: tar-stream@^1.1.2: version "1.6.2" - resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== dependencies: bl "^1.0.0" @@ -5125,7 +4994,7 @@ tar-stream@^1.1.2: tar-stream@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== dependencies: bl "^4.0.3" @@ -5136,7 +5005,7 @@ tar-stream@^2.2.0: tar@^6.1.11, tar@^6.1.2: version "6.2.1" - resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== dependencies: chownr "^2.0.0" @@ -5148,14 +5017,14 @@ tar@^6.1.11, tar@^6.1.2: tdigest@^0.1.1: version "0.1.2" - resolved "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz" + resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.2.tgz#96c64bac4ff10746b910b0e23b515794e12faced" integrity sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA== dependencies: bintrees "1.0.2" test-exclude@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" @@ -5164,17 +5033,17 @@ test-exclude@^6.0.0: text-hex@1.0.x: version "1.0.0" - resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== text-table@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== thriftrw@^3.5.0: version "3.11.4" - resolved "https://registry.npmjs.org/thriftrw/-/thriftrw-3.11.4.tgz" + resolved "https://registry.yarnpkg.com/thriftrw/-/thriftrw-3.11.4.tgz#84c990ee89e926631c0b475909ada44ee9249870" integrity sha512-UcuBd3eanB3T10nXWRRMwfwoaC6VMk7qe3/5YIWP2Jtw+EbHqJ0p1/K3x8ixiR5dozKSSfcg1W+0e33G1Di3XA== dependencies: bufrw "^1.2.1" @@ -5183,64 +5052,64 @@ thriftrw@^3.5.0: tiny-case@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== tmp@^0.2.0: version "0.2.3" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== tmpl@1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-buffer@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" toidentifier@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== toposort@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== "traverse@>=0.3.0 <0.4": version "0.3.9" - resolved "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" integrity sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ== tree-kill@^1.2.2: version "1.2.2" - resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== triple-beam@^1.3.0: version "1.4.1" - resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== ts-node-dev@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-2.0.0.tgz#bdd53e17ab3b5d822ef519928dc6b4a7e0f13065" integrity sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w== dependencies: chokidar "^3.5.1" @@ -5254,9 +5123,9 @@ ts-node-dev@2.0.0: ts-node "^10.4.0" tsconfig "^7.0.0" -ts-node@^10.4.0, ts-node@>=9.0.0: +ts-node@^10.4.0: version "10.9.2" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== dependencies: "@cspotcode/source-map-support" "^0.8.0" @@ -5275,7 +5144,7 @@ ts-node@^10.4.0, ts-node@>=9.0.0: tsconfig@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== dependencies: "@types/strip-bom" "^3.0.0" @@ -5285,90 +5154,95 @@ tsconfig@^7.0.0: tunnel-agent@^0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== dependencies: safe-buffer "^5.0.1" type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: prelude-ls "^1.2.1" type-check@~0.3.2: version "0.3.2" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== dependencies: prelude-ls "~1.1.2" type-detect@4.0.8: version "4.0.8" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== type-fest@^0.21.3: version "0.21.3" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== type-fest@^0.8.1: version "0.8.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== type-fest@^2.19.0: version "2.19.0" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== type-is@~1.6.18: version "1.6.18" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: media-typer "0.3.0" mime-types "~2.1.24" -typescript@*, typescript@>=2.7, typescript@5.4.2: +typescript@5.4.2: version "5.4.2" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== underscore@1.12.1: version "1.12.1" - resolved "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== undici-types@~5.26.4: version "5.26.5" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + unique-filename@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea" integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g== dependencies: unique-slug "^4.0.0" unique-slug@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-4.0.0.tgz#6bae6bb16be91351badd24cdce741f892a6532e3" integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ== dependencies: imurmurhash "^0.1.4" -unpipe@~1.0.0, unpipe@1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unzipper@^0.10.11: version "0.10.14" - resolved "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz" + resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.14.tgz#d2b33c977714da0fbc0f82774ad35470a7c962b1" integrity sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g== dependencies: big-integer "^1.6.17" @@ -5382,65 +5256,60 @@ unzipper@^0.10.11: readable-stream "~2.3.6" setimmediate "~1.0.4" -update-browserslist-db@^1.0.13: - version "1.0.16" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz" - integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== dependencies: escalade "^3.1.2" picocolors "^1.0.1" -uri-js@^4.2.2, uri-js@^4.4.1: +uri-js@^4.2.2: version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== utils-merge@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + uuid@^3.0.0: version "3.4.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.0: - version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -uuid@^8.3.2: +uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@9.0.1: - version "9.0.1" - resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" - integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== - v8-compile-cache-lib@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== v8-compile-cache@^2.0.3: version "2.4.0" - resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== v8-to-istanbul@^9.0.1: - version "9.2.0" - resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz" - integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" @@ -5448,54 +5317,54 @@ v8-to-istanbul@^9.0.1: vary@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== walker@^1.0.8: version "1.0.8" - resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: makeerror "1.0.12" which-pm-runs@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.1.0.tgz#35ccf7b1a0fce87bd8b92a478c9d045785d3bf35" integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== which@^2.0.1: version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" which@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/which/-/which-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== dependencies: isexe "^3.1.1" wide-align@^1.1.0: version "1.1.5" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== dependencies: string-width "^1.0.2 || 2 || 3 || 4" winston-transport@^4.7.0: - version "4.7.0" - resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz" - integrity sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg== + version "4.7.1" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.1.tgz#52ff1bcfe452ad89991a0aaff9c3b18e7f392569" + integrity sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA== dependencies: - logform "^2.3.2" - readable-stream "^3.6.0" + logform "^2.6.1" + readable-stream "^3.6.2" triple-beam "^1.3.0" winston@3.12.0: version "3.12.0" - resolved "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.12.0.tgz#a5d965a41d3dc31be5408f8c66e927958846c0d0" integrity sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w== dependencies: "@colors/colors" "^1.6.0" @@ -5512,31 +5381,22 @@ winston@3.12.0: wmf@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da" integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw== word-wrap@^1.2.5, word-wrap@~1.2.3: version "1.2.5" - resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== word@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/word/-/word-0.3.0.tgz" + resolved "https://registry.yarnpkg.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961" integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -5545,7 +5405,7 @@ wrap-ansi@^7.0.0: wrap-ansi@^8.1.0: version "8.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: ansi-styles "^6.1.0" @@ -5554,12 +5414,12 @@ wrap-ansi@^8.1.0: wrappy@1: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^4.0.2: version "4.0.2" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== dependencies: imurmurhash "^0.1.4" @@ -5567,7 +5427,7 @@ write-file-atomic@^4.0.2: xlsx-populate@1.21.0: version "1.21.0" - resolved "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz" + resolved "https://registry.yarnpkg.com/xlsx-populate/-/xlsx-populate-1.21.0.tgz#f6cd02401f4cd3d055e81f2b6983ddfeeb60ffe6" integrity sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw== dependencies: cfb "^1.1.3" @@ -5577,7 +5437,7 @@ xlsx-populate@1.21.0: xlsx@*, xlsx@0.18.5: version "0.18.5" - resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz" + resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0" integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ== dependencies: adler-32 "~1.3.0" @@ -5590,42 +5450,42 @@ xlsx@*, xlsx@0.18.5: xmlchars@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== xorshift@^1.1.1: version "1.2.0" - resolved "https://registry.npmjs.org/xorshift/-/xorshift-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/xorshift/-/xorshift-1.2.0.tgz#30a4cdd8e9f8d09d959ed2a88c42a09c660e8148" integrity sha512-iYgNnGyeeJ4t6U11NpA/QiKy+PXn5Aa3Azg5qkwIFz1tBLllQrjjsk9yzD7IAK0naNU4JxdeDgqW9ov4u/hc4g== xtend@^4.0.0, xtend@~4.0.0: version "4.0.2" - resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== y18n@^5.0.5: version "5.0.8" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== yallist@^3.0.2: version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yallist@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yargs-parser@^21.1.1: version "21.1.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== yargs@^17.3.1: version "17.7.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" @@ -5638,17 +5498,17 @@ yargs@^17.3.1: yn@3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== yup@1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/yup/-/yup-1.4.0.tgz#898dcd660f9fb97c41f181839d3d65c3ee15a43e" integrity sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg== dependencies: property-expr "^2.0.5" @@ -5658,7 +5518,7 @@ yup@1.4.0: zip-stream@^4.1.0: version "4.1.1" - resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.1.tgz#1337fe974dbaffd2fa9a1ba09662a66932bd7135" integrity sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ== dependencies: archiver-utils "^3.0.4" From fd9a00f0e76497bdaf533142fc3c56e12b07bee0 Mon Sep 17 00:00:00 2001 From: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:59:19 +0530 Subject: [PATCH 14/29] HCMPRE-1635 Microplanning v0.1 master merge (#1271) --- health-services/census-service/CHANGELOG.md | 13 + health-services/census-service/README.md | 18 + health-services/census-service/pom.xml | 141 ++++ .../src/main/java/digit/Main.java | 20 + .../main/java/digit/config/Configuration.java | 86 +++ .../java/digit/config/MainConfiguration.java | 41 ++ .../java/digit/config/ServiceConstants.java | 114 +++ .../kafka/FacilityCatchmentConsumer.java | 99 +++ .../src/main/java/digit/kafka/Producer.java | 20 + .../digit/kafka/ResourceCensusConsumer.java | 37 + .../digit/repository/CensusRepository.java | 21 + .../repository/ServiceRequestRepository.java | 45 ++ .../repository/impl/CensusRepositoryImpl.java | 219 ++++++ .../querybuilder/CensusQueryBuilder.java | 219 ++++++ .../repository/rowmapper/CensusRowMapper.java | 148 ++++ .../rowmapper/StatusCountRowMapper.java | 30 + .../java/digit/service/CensusService.java | 127 ++++ .../service/enrichment/CensusEnrichment.java | 218 ++++++ .../enrichment/CensusTimeframeEnrichment.java | 47 ++ .../service/validator/CensusValidator.java | 337 +++++++++ .../service/workflow/WorkflowService.java | 331 +++++++++ .../main/java/digit/util/BoundaryUtil.java | 111 +++ .../java/digit/util/BusinessServiceUtil.java | 81 +++ .../src/main/java/digit/util/CommonUtil.java | 151 ++++ .../util/PlanEmployeeAssignmnetUtil.java | 59 ++ .../src/main/java/digit/util/QueryUtil.java | 139 ++++ .../java/digit/util/ResponseInfoFactory.java | 27 + .../web/controllers/CensusController.java | 76 ++ .../digit/web/models/AdditionalField.java} | 27 +- .../digit/web/models/BulkCensusRequest.java | 33 + .../main/java/digit/web/models/Census.java | 142 ++++ .../main/java/digit/web/models/CensusDTO.java | 104 +++ .../java/digit/web/models/CensusRequest.java | 31 + .../digit/web/models/CensusRequestDTO.java | 31 + .../java/digit/web/models/CensusResponse.java | 42 ++ .../web/models/CensusSearchCriteria.java | 72 ++ .../digit/web/models/CensusSearchRequest.java | 33 + .../web/models/PopulationByDemographic.java | 69 ++ .../digit/web/models/RequestInfoWrapper.java | 18 + .../boundary/BoundarySearchResponse.java | 42 ++ .../boundary/BoundaryTypeHierarchy.java | 30 + .../BoundaryTypeHierarchyDefinition.java | 45 ++ .../BoundaryTypeHierarchyResponse.java | 36 + .../BoundaryTypeHierarchySearchCriteria.java | 38 + .../BoundaryTypeHierarchySearchRequest.java | 33 + .../web/models/boundary/EnrichedBoundary.java | 42 ++ .../models/boundary/HierarchyRelation.java | 34 + .../models/plan/PlanEmployeeAssignment.java | 63 ++ .../plan/PlanEmployeeAssignmentResponse.java | 37 + .../PlanEmployeeAssignmentSearchCriteria.java | 50 ++ .../PlanEmployeeAssignmentSearchRequest.java | 29 + .../web/models/plan/PlanFacilityDTO.java | 72 ++ .../models/plan/PlanFacilityRequestDTO.java | 33 + .../src/main/resources/application.properties | 82 +++ .../src/main/resources/db/Dockerfile | 9 + .../src/main/resources/db/migrate.sh | 2 +- .../V20240925155908__census_create_ddl.sql | 36 + ...00__census_additional_field_create_ddl.sql | 12 + ...0700__alter_census_assignee_create_ddl.sql | 1 + .../src/main/resources/start.sh | 11 + .../test/java/digit/TestConfiguration.java | 16 + .../web/controllers/CensusControllerTest.java | 69 ++ health-services/plan-service/CHANGELOG.md | 42 +- health-services/plan-service/pom.xml | 11 + .../src/main/java/digit/Main.java | 2 +- .../main/java/digit/config/Configuration.java | 88 ++- .../java/digit/config/ServiceConstants.java | 304 +++++++- ...jectFactoryCreatePlanFacilityConsumer.java | 57 ++ .../digit/kafka/UpdatePlanConfigConsumer.java | 1 + .../PlanConfigurationRepository.java | 1 + .../PlanEmployeeAssignmentRepository.java | 16 + .../repository/PlanFacilityRepository.java | 15 + .../java/digit/repository/PlanRepository.java | 10 +- .../repository/ServiceRequestRepository.java | 5 +- .../impl/PlanEmployeeAssignmentImpl.java | 121 ++++ .../impl/PlanFacilityRepositoryImpl.java | 150 ++++ .../repository/impl/PlanRepositoryImpl.java | 124 +++- .../querybuilder/PlanConfigQueryBuilder.java | 62 +- .../PlanEmployeeAssignmentQueryBuilder.java | 170 +++++ .../PlanFacilityQueryBuilder.java | 154 ++++ .../querybuilder/PlanQueryBuilder.java | 136 +++- .../rowmapper/PlanConfigRowMapper.java | 87 ++- .../PlanEmployeeAssignmentRowMapper.java | 66 ++ .../rowmapper/PlanFacilityRowMapper.java | 79 ++ .../repository/rowmapper/PlanRowMapper.java | 88 +-- .../rowmapper/PlanStatusCountRowMapper.java | 31 + .../service/PlanConfigurationService.java | 54 +- .../digit/service/PlanEmployeeService.java | 91 +++ .../main/java/digit/service/PlanEnricher.java | 130 +++- .../digit/service/PlanFacilityService.java | 98 +++ .../main/java/digit/service/PlanService.java | 48 +- .../java/digit/service/PlanValidator.java | 457 +++++++++--- .../service/enrichment/EnrichmentService.java | 237 +++--- .../PlanEmployeeAssignmentEnricher.java | 71 ++ .../enrichment/PlanFacilityEnricher.java | 213 ++++++ .../validator/PlanConfigurationValidator.java | 675 +++++++++++------- .../PlanEmployeeAssignmentValidator.java | 349 +++++++++ .../validator/PlanFacilityValidator.java | 301 ++++++++ .../service/validator/WorkflowValidator.java | 141 ++++ .../service/workflow/WorkflowService.java | 432 +++++++++++ .../main/java/digit/util/BoundaryUtil.java | 111 +++ .../main/java/digit/util/CampaignUtil.java | 91 +++ .../src/main/java/digit/util/CensusUtil.java | 60 ++ .../src/main/java/digit/util/CommonUtil.java | 275 +++++++ .../main/java/digit/util/FacilityUtil.java | 84 +++ .../src/main/java/digit/util/MdmsUtil.java | 38 +- .../src/main/java/digit/util/MdmsV2Util.java | 76 ++ .../src/main/java/digit/util/QueryUtil.java | 91 ++- .../src/main/java/digit/util/ServiceUtil.java | 12 + .../src/main/java/digit/util/UserUtil.java | 73 ++ .../web/controllers/PlanConfigController.java | 9 +- .../digit/web/controllers/PlanController.java | 17 +- .../controllers/PlanEmployeeController.java | 62 ++ .../controllers/PlanFacilityController.java | 61 ++ .../java/digit/web/models/Assumption.java | 13 +- .../digit/web/models/BulkPlanRequest.java | 33 + .../src/main/java/digit/web/models/File.java | 12 +- .../java/digit/web/models/MetricDetail.java | 11 +- .../main/java/digit/web/models/Operation.java | 32 +- .../java/digit/web/models/Pagination.java | 35 + .../src/main/java/digit/web/models/Plan.java | 30 +- .../digit/web/models/PlanConfiguration.java | 39 +- .../PlanConfigurationSearchCriteria.java | 13 +- .../main/java/digit/web/models/PlanDTO.java | 90 +++ .../web/models/PlanEmployeeAssignment.java | 71 ++ .../web/models/PlanEmployeeAssignmentDTO.java | 69 ++ .../models/PlanEmployeeAssignmentRequest.java | 30 + .../PlanEmployeeAssignmentRequestDTO.java | 30 + .../PlanEmployeeAssignmentResponse.java | 36 + .../PlanEmployeeAssignmentSearchCriteria.java | 72 ++ .../PlanEmployeeAssignmentSearchRequest.java | 29 + .../java/digit/web/models/PlanFacility.java | 92 +++ .../digit/web/models/PlanFacilityDTO.java | 79 ++ .../digit/web/models/PlanFacilityRequest.java | 33 + .../web/models/PlanFacilityRequestDTO.java | 33 + .../web/models/PlanFacilityResponse.java | 33 + .../models/PlanFacilitySearchCriteria.java | 64 ++ .../web/models/PlanFacilitySearchRequest.java | 34 + .../java/digit/web/models/PlanRequestDTO.java | 29 + .../java/digit/web/models/PlanResponse.java | 10 + .../digit/web/models/PlanSearchCriteria.java | 29 +- .../digit/web/models/RequestInfoWrapper.java | 18 + .../main/java/digit/web/models/Resource.java | 2 +- .../main/java/digit/web/models/Source.java | 5 + .../boundary/BoundarySearchResponse.java | 42 ++ .../boundary/BoundaryTypeHierarchy.java | 30 + .../BoundaryTypeHierarchyDefinition.java | 45 ++ .../BoundaryTypeHierarchyResponse.java | 36 + .../BoundaryTypeHierarchySearchCriteria.java | 39 + .../BoundaryTypeHierarchySearchRequest.java | 31 + .../web/models/boundary/EnrichedBoundary.java | 42 ++ .../models/boundary/HierarchyRelation.java | 34 + .../web/models/census/AdditionalField.java | 48 ++ .../java/digit/web/models/census/Census.java | 139 ++++ .../web/models/census/CensusResponse.java | 42 ++ .../models/census/CensusSearchCriteria.java | 72 ++ .../models/census/CensusSearchRequest.java | 31 + .../census/PopulationByDemographic.java | 69 ++ .../web/models/facility/AdditionalFields.java | 25 + .../digit/web/models/facility/Address.java | 62 ++ .../digit/web/models/facility/Facility.java | 64 ++ .../web/models/facility/FacilityDetail.java | 19 + .../web/models/facility/FacilityResponse.java | 22 + .../facility/FacilitySearchCriteria.java | 30 + .../facility/FacilitySearchRequest.java | 20 + .../java/digit/web/models/facility/Field.java | 20 + .../digit/web/models/facility/Locality.java | 33 + .../java/digit/web/models/mdmsV2/Mdms.java | 55 ++ .../web/models/mdmsV2/MdmsCriteriaReqV2.java | 23 + .../web/models/mdmsV2/MdmsCriteriaV2.java | 62 ++ .../web/models/mdmsV2/MdmsResponseV2.java | 25 + .../web/models/projectFactory/Boundary.java | 32 + .../models/projectFactory/CampaignDetail.java | 85 +++ .../projectFactory/CampaignResponse.java | 29 + .../CampaignSearchCriteria.java | 51 ++ .../projectFactory/CampaignSearchReq.java | 22 + .../web/models/projectFactory/Condition.java | 27 + .../models/projectFactory/DeliveryRule.java | 43 ++ .../web/models/projectFactory/Pagination.java | 35 + .../web/models/projectFactory/Product.java | 26 + .../web/models/projectFactory/Resource.java | 32 + .../src/main/resources/application.properties | 50 +- .../src/main/resources/db/Dockerfile | 4 +- .../src/main/resources/db/migrate.sh | 2 +- ...5113045__plan_configuration_create_ddl.sql | 40 +- .../main/V20240305113047__plan_create_ddl.sql | 5 +- ...plan_configuration_add_filestoreid_ddl.sql | 1 - ...figuration_add_template_identifier_ddl.sql | 1 - ...240923113045__plan_facility_create_ddl.sql | 19 + ...000__plan_configuration_add_status_ddl.sql | 2 - ...000__plan_configuration_add_active_ddl.sql | 11 - ...0__plan_employee_assignment_create_ddl.sql | 19 + ...115700__alter_plan_assignee_create_ddl.sql | 1 + ...cility_add_boundary_ancestral_path_ddl.sql | 1 + .../resource-estimation-service/CHANGELOG.md | 8 - .../processor/config/ServiceConstants.java | 72 -- .../processor/web/models/MetricDetail.java | 34 - .../resource-generator/CHANGELOG.md | 13 + .../LOCALSETUP.md | 0 .../README.md | 0 .../pom.xml | 8 +- .../main/java/org/egov/processor/Main.java | 0 .../egov/processor/config/Configuration.java | 67 +- .../processor/config/MainConfiguration.java | 0 .../processor/config/ServiceConstants.java | 123 ++++ .../egov/processor/kafka/PlanConsumer.java | 17 +- .../org/egov/processor/kafka/Producer.java | 0 .../repository/ServiceRequestRepository.java | 0 .../egov/processor/service/ExcelParser.java | 364 +++++----- .../egov/processor/service/FileParser.java | 0 .../egov/processor/service/GeoJsonParser.java | 0 .../service/ResourceEstimationService.java | 27 +- .../processor/service/ShapeFileParser.java | 0 .../org/egov/processor/util/BoundaryUtil.java | 0 .../egov/processor/util/CalculationUtil.java | 58 +- .../util/CampaignIntegrationUtil.java | 210 ++++-- .../org/egov/processor/util/CensusUtil.java | 191 +++++ .../egov/processor/util/EnrichmentUtil.java | 295 ++++++++ .../egov/processor/util/FilestoreUtil.java | 0 .../org/egov/processor/util/LocaleUtil.java | 18 +- .../org/egov/processor/util/MdmsUtil.java | 2 +- .../org/egov/processor/util/MdmsV2Util.java | 79 ++ .../org/egov/processor/util/ParsingUtil.java | 202 +++++- .../processor/util/PlanConfigurationUtil.java | 18 +- .../org/egov/processor/util/PlanUtil.java | 84 ++- .../org/egov/processor/web/PlanResponse.java | 42 ++ .../processor/web/PlanSearchCriteria.java | 57 ++ .../egov/processor/web/PlanSearchRequest.java | 30 + .../web/controllers/FileController.java | 0 .../egov/processor/web/models/Activity.java | 12 +- .../egov/processor/web/models/Assumption.java | 58 ++ .../egov/processor/web/models/Condition.java | 6 +- .../org/egov/processor/web/models/File.java | 27 +- .../org/egov/processor/web/models/Locale.java | 0 .../processor/web/models/LocaleResponse.java | 0 .../processor/web/models/MetricDetail.java | 75 ++ .../egov/processor/web/models/Operation.java | 38 +- .../org/egov/processor/web/models/Plan.java | 36 +- .../web/models/PlanConfiguration.java | 38 +- .../web/models/PlanConfigurationRequest.java | 0 .../web/models/PlanConfigurationResponse.java | 0 .../PlanConfigurationSearchCriteria.java | 0 .../PlanConfigurationSearchRequest.java | 0 .../processor/web/models/PlanRequest.java | 0 .../egov/processor/web/models/Resource.java | 8 +- .../processor/web/models/ResourceMapping.java | 7 +- .../org/egov/processor/web/models/Source.java | 5 + .../org/egov/processor/web/models/Target.java | 6 +- .../boundary/BoundarySearchResponse.java | 0 .../web/models/boundary/EnrichedBoundary.java | 0 .../models/boundary/HierarchyRelation.java | 0 .../campaignManager/AdditionalDetails.java | 0 .../web/models/campaignManager/Boundary.java | 0 .../web/models/campaignManager/Campaign.java | 18 +- .../campaignManager/CampaignCondition.java | 0 .../campaignManager/CampaignDetails.java | 0 .../campaignManager/CampaignRequest.java | 0 .../campaignManager/CampaignResources.java | 0 .../campaignManager/CampaignResponse.java | 0 .../CampaignSearchRequest.java | 0 .../campaignManager/CycleConfigureDate.java | 0 .../web/models/campaignManager/CycleData.java | 0 .../models/campaignManager/DeliveryRule.java | 0 .../campaignManager/MicroplanDetails.java | 32 + .../MicroplanDetailsRequest.java | 26 + .../web/models/campaignManager/Product.java | 0 .../campaignManager/ResourceDetails.java | 48 ++ .../ResourceDetailsRequest.java | 30 + .../web/models/census/AdditionalField.java | 48 ++ .../processor/web/models/census/Census.java | 138 ++++ .../web/models/census/CensusRequest.java | 31 + .../web/models/census/CensusResponse.java | 41 ++ .../models/census/CensusSearchCriteria.java | 71 ++ .../models/census/CensusSearchRequest.java | 31 + .../census/PopulationByDemographic.java | 69 ++ .../processor/web/models/mdmsV2/Mdms.java | 55 ++ .../web/models/mdmsV2/MdmsCriteriaReqV2.java | 26 + .../web/models/mdmsV2/MdmsCriteriaV2.java | 62 ++ .../web/models/mdmsV2/MdmsResponseV2.java | 28 + .../src/main/resources/application.properties | 33 +- .../src/main/resources/db/Dockerfile | 2 +- .../src/main/resources/db/migrate.sh | 3 + 282 files changed, 15144 insertions(+), 1363 deletions(-) create mode 100644 health-services/census-service/CHANGELOG.md create mode 100644 health-services/census-service/README.md create mode 100644 health-services/census-service/pom.xml create mode 100644 health-services/census-service/src/main/java/digit/Main.java create mode 100644 health-services/census-service/src/main/java/digit/config/Configuration.java create mode 100644 health-services/census-service/src/main/java/digit/config/MainConfiguration.java create mode 100644 health-services/census-service/src/main/java/digit/config/ServiceConstants.java create mode 100644 health-services/census-service/src/main/java/digit/kafka/FacilityCatchmentConsumer.java create mode 100644 health-services/census-service/src/main/java/digit/kafka/Producer.java create mode 100644 health-services/census-service/src/main/java/digit/kafka/ResourceCensusConsumer.java create mode 100644 health-services/census-service/src/main/java/digit/repository/CensusRepository.java create mode 100644 health-services/census-service/src/main/java/digit/repository/ServiceRequestRepository.java create mode 100644 health-services/census-service/src/main/java/digit/repository/impl/CensusRepositoryImpl.java create mode 100644 health-services/census-service/src/main/java/digit/repository/querybuilder/CensusQueryBuilder.java create mode 100644 health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java create mode 100644 health-services/census-service/src/main/java/digit/repository/rowmapper/StatusCountRowMapper.java create mode 100644 health-services/census-service/src/main/java/digit/service/CensusService.java create mode 100644 health-services/census-service/src/main/java/digit/service/enrichment/CensusEnrichment.java create mode 100644 health-services/census-service/src/main/java/digit/service/enrichment/CensusTimeframeEnrichment.java create mode 100644 health-services/census-service/src/main/java/digit/service/validator/CensusValidator.java create mode 100644 health-services/census-service/src/main/java/digit/service/workflow/WorkflowService.java create mode 100644 health-services/census-service/src/main/java/digit/util/BoundaryUtil.java create mode 100644 health-services/census-service/src/main/java/digit/util/BusinessServiceUtil.java create mode 100644 health-services/census-service/src/main/java/digit/util/CommonUtil.java create mode 100644 health-services/census-service/src/main/java/digit/util/PlanEmployeeAssignmnetUtil.java create mode 100644 health-services/census-service/src/main/java/digit/util/QueryUtil.java create mode 100644 health-services/census-service/src/main/java/digit/util/ResponseInfoFactory.java create mode 100644 health-services/census-service/src/main/java/digit/web/controllers/CensusController.java rename health-services/{resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java => census-service/src/main/java/digit/web/models/AdditionalField.java} (52%) create mode 100644 health-services/census-service/src/main/java/digit/web/models/BulkCensusRequest.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/Census.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/CensusDTO.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/CensusRequest.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/CensusRequestDTO.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/CensusResponse.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/CensusSearchCriteria.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/CensusSearchRequest.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/PopulationByDemographic.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/RequestInfoWrapper.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignment.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentResponse.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchCriteria.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchRequest.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityDTO.java create mode 100644 health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityRequestDTO.java create mode 100644 health-services/census-service/src/main/resources/application.properties create mode 100644 health-services/census-service/src/main/resources/db/Dockerfile rename health-services/{resource-estimation-service => census-service}/src/main/resources/db/migrate.sh (67%) create mode 100644 health-services/census-service/src/main/resources/db/migration/main/V20240925155908__census_create_ddl.sql create mode 100644 health-services/census-service/src/main/resources/db/migration/main/V20241105152700__census_additional_field_create_ddl.sql create mode 100644 health-services/census-service/src/main/resources/db/migration/main/V20241126120700__alter_census_assignee_create_ddl.sql create mode 100644 health-services/census-service/src/main/resources/start.sh create mode 100644 health-services/census-service/src/test/java/digit/TestConfiguration.java create mode 100644 health-services/census-service/src/test/java/digit/web/controllers/CensusControllerTest.java create mode 100644 health-services/plan-service/src/main/java/digit/kafka/ProjectFactoryCreatePlanFacilityConsumer.java create mode 100644 health-services/plan-service/src/main/java/digit/repository/PlanEmployeeAssignmentRepository.java create mode 100644 health-services/plan-service/src/main/java/digit/repository/PlanFacilityRepository.java create mode 100644 health-services/plan-service/src/main/java/digit/repository/impl/PlanEmployeeAssignmentImpl.java create mode 100644 health-services/plan-service/src/main/java/digit/repository/impl/PlanFacilityRepositoryImpl.java create mode 100644 health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanEmployeeAssignmentQueryBuilder.java create mode 100644 health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanFacilityQueryBuilder.java create mode 100644 health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanEmployeeAssignmentRowMapper.java create mode 100644 health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanFacilityRowMapper.java create mode 100644 health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanStatusCountRowMapper.java create mode 100644 health-services/plan-service/src/main/java/digit/service/PlanEmployeeService.java create mode 100644 health-services/plan-service/src/main/java/digit/service/PlanFacilityService.java create mode 100644 health-services/plan-service/src/main/java/digit/service/enrichment/PlanEmployeeAssignmentEnricher.java create mode 100644 health-services/plan-service/src/main/java/digit/service/enrichment/PlanFacilityEnricher.java create mode 100644 health-services/plan-service/src/main/java/digit/service/validator/PlanEmployeeAssignmentValidator.java create mode 100644 health-services/plan-service/src/main/java/digit/service/validator/PlanFacilityValidator.java create mode 100644 health-services/plan-service/src/main/java/digit/service/validator/WorkflowValidator.java create mode 100644 health-services/plan-service/src/main/java/digit/service/workflow/WorkflowService.java create mode 100644 health-services/plan-service/src/main/java/digit/util/BoundaryUtil.java create mode 100644 health-services/plan-service/src/main/java/digit/util/CampaignUtil.java create mode 100644 health-services/plan-service/src/main/java/digit/util/CensusUtil.java create mode 100644 health-services/plan-service/src/main/java/digit/util/CommonUtil.java create mode 100644 health-services/plan-service/src/main/java/digit/util/FacilityUtil.java create mode 100644 health-services/plan-service/src/main/java/digit/util/MdmsV2Util.java create mode 100644 health-services/plan-service/src/main/java/digit/util/ServiceUtil.java create mode 100644 health-services/plan-service/src/main/java/digit/util/UserUtil.java create mode 100644 health-services/plan-service/src/main/java/digit/web/controllers/PlanEmployeeController.java create mode 100644 health-services/plan-service/src/main/java/digit/web/controllers/PlanFacilityController.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/BulkPlanRequest.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/Pagination.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanDTO.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignment.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentDTO.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequest.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequestDTO.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentResponse.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchCriteria.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchRequest.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanFacility.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanFacilityDTO.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequest.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequestDTO.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanFacilityResponse.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchCriteria.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchRequest.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/PlanRequestDTO.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/RequestInfoWrapper.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/Source.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/census/AdditionalField.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/census/Census.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/census/CensusResponse.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchCriteria.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchRequest.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/census/PopulationByDemographic.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/facility/AdditionalFields.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/facility/Address.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/facility/Facility.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/facility/FacilityDetail.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/facility/FacilityResponse.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchCriteria.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchRequest.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/facility/Field.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/facility/Locality.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/mdmsV2/Mdms.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaReqV2.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaV2.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsResponseV2.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/projectFactory/Boundary.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignDetail.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignResponse.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchCriteria.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchReq.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/projectFactory/Condition.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/projectFactory/DeliveryRule.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/projectFactory/Pagination.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/projectFactory/Product.java create mode 100644 health-services/plan-service/src/main/java/digit/web/models/projectFactory/Resource.java delete mode 100644 health-services/plan-service/src/main/resources/db/migration/main/V20240404113045__plan_configuration_add_filestoreid_ddl.sql delete mode 100644 health-services/plan-service/src/main/resources/db/migration/main/V20240404150000__plan_configuration_add_template_identifier_ddl.sql create mode 100644 health-services/plan-service/src/main/resources/db/migration/main/V20240923113045__plan_facility_create_ddl.sql delete mode 100644 health-services/plan-service/src/main/resources/db/migration/main/V20241604150000__plan_configuration_add_status_ddl.sql delete mode 100644 health-services/plan-service/src/main/resources/db/migration/main/V20242105150000__plan_configuration_add_active_ddl.sql create mode 100644 health-services/plan-service/src/main/resources/db/migration/main/V20242109141800__plan_employee_assignment_create_ddl.sql create mode 100644 health-services/plan-service/src/main/resources/db/migration/main/V20242110115700__alter_plan_assignee_create_ddl.sql create mode 100644 health-services/plan-service/src/main/resources/db/migration/main/V20242112141500__alter plan_facility_add_boundary_ancestral_path_ddl.sql delete mode 100644 health-services/resource-estimation-service/CHANGELOG.md delete mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java delete mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java create mode 100644 health-services/resource-generator/CHANGELOG.md rename health-services/{resource-estimation-service => resource-generator}/LOCALSETUP.md (100%) rename health-services/{resource-estimation-service => resource-generator}/README.md (100%) rename health-services/{resource-estimation-service => resource-generator}/pom.xml (95%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/Main.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/config/Configuration.java (54%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/config/MainConfiguration.java (100%) create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/kafka/PlanConsumer.java (66%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/kafka/Producer.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/service/ExcelParser.java (74%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/service/FileParser.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/service/GeoJsonParser.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/service/ResourceEstimationService.java (82%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/service/ShapeFileParser.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/util/BoundaryUtil.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/util/CalculationUtil.java (74%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java (61%) create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/util/CensusUtil.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/util/FilestoreUtil.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/util/LocaleUtil.java (89%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/util/MdmsUtil.java (99%) create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsV2Util.java rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/util/ParsingUtil.java (59%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java (85%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/util/PlanUtil.java (70%) create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/PlanResponse.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchCriteria.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchRequest.java rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/controllers/FileController.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/Activity.java (99%) create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/Assumption.java rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/Condition.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/File.java (81%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/Locale.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/LocaleResponse.java (100%) create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/MetricDetail.java rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/Operation.java (70%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/Plan.java (63%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/PlanConfiguration.java (68%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/PlanRequest.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/Resource.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/ResourceMapping.java (99%) create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/Source.java rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/Target.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java (94%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java (100%) rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java (100%) create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetails.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetailsRequest.java rename health-services/{resource-estimation-service => resource-generator}/src/main/java/org/egov/processor/web/models/campaignManager/Product.java (100%) create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetails.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetailsRequest.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/AdditionalField.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/Census.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusRequest.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusResponse.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchCriteria.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchRequest.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/PopulationByDemographic.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/Mdms.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaReqV2.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaV2.java create mode 100644 health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsResponseV2.java rename health-services/{resource-estimation-service => resource-generator}/src/main/resources/application.properties (68%) rename health-services/{resource-estimation-service => resource-generator}/src/main/resources/db/Dockerfile (83%) create mode 100644 health-services/resource-generator/src/main/resources/db/migrate.sh diff --git a/health-services/census-service/CHANGELOG.md b/health-services/census-service/CHANGELOG.md new file mode 100644 index 00000000000..38562489c90 --- /dev/null +++ b/health-services/census-service/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 1.0.0 - 2024-11-28 +#### Census Service +The Census Service introduces core functionalities for managing census data: + +1. Validation of Census: Ensures data integrity by validating all census requests before processing. +2. Census Create: Creates new census records after validation and enrichment, publishing request to the designated Kafka topic to handle the creation process asynchronously. +3. Census Update: Updates existing records post-validation and enrichment by sending request to the designated Kafka update topic. +4. Census Bulk Update: Updates multiple census records in one operation after successful validation. +5. Census Search: Enables searching for census records with the provided search criteria. +6. Plan Facility Consumer: Listens to Plan Facility Update topic to assign facility to a boundary in census. \ No newline at end of file diff --git a/health-services/census-service/README.md b/health-services/census-service/README.md new file mode 100644 index 00000000000..a2e8a9f7b84 --- /dev/null +++ b/health-services/census-service/README.md @@ -0,0 +1,18 @@ +# Swagger generated server + +Spring Boot Server + + +## Overview +This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/swagger-api/swagger-core), you can easily generate a server stub. +This is an example of building a swagger-enabled server in Java using the SpringBoot framework. + +The underlying library integrating swagger to SpringBoot is [springfox](https://github.com/springfox/springfox) + +Start your server as an simple java application + +You can view the api documentation in swagger-ui by pointing to +http://localhost:8080/ + +Change default port value in application.properties \ No newline at end of file diff --git a/health-services/census-service/pom.xml b/health-services/census-service/pom.xml new file mode 100644 index 00000000000..7e6f7adc8fb --- /dev/null +++ b/health-services/census-service/pom.xml @@ -0,0 +1,141 @@ + + 4.0.0 + org.egov + census-service + jar + census-service + 1.0.0 + + 17 + ${java.version} + ${java.version} + + + org.springframework.boot + spring-boot-starter-parent + 3.2.2 + + + src/main/java + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.egov.common + health-services-models + 1.0.21-SNAPSHOT + compile + + + junit + junit + 4.13.2 + test + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.flywaydb + flyway-core + 9.22.3 + + + org.postgresql + postgresql + 42.7.1 + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.swagger + swagger-core + 1.5.18 + + + io.swagger.core.v3 + swagger-annotations + 2.2.8 + + + net.minidev + json-smart + 2.5.0 + + + + org.egov.services + tracer + 2.9.0-SNAPSHOT + + + + + + + + org.egov + mdms-client + 2.9.0-SNAPSHOT + compile + + + org.projectlombok + lombok + true + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + org.springframework.boot + spring-boot-starter-validation + + + + + repo.egovernments.org + eGov ERP Releases Repository + https://nexus-repo.egovernments.org/nexus/content/repositories/releases/ + + + repo.egovernments.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.egovernments.org/nexus/content/repositories/snapshots/ + + + repo.egovernments.org.public + eGov Public Repository Group + https://nexus-repo.egovernments.org/nexus/content/groups/public/ + + + repo.digit.org + eGov DIGIT Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + diff --git a/health-services/census-service/src/main/java/digit/Main.java b/health-services/census-service/src/main/java/digit/Main.java new file mode 100644 index 00000000000..6e3d79db11c --- /dev/null +++ b/health-services/census-service/src/main/java/digit/Main.java @@ -0,0 +1,20 @@ +package digit; + + +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; + +@Import({ TracerConfiguration.class }) +@SpringBootApplication +@ComponentScan(basePackages = { "digit", "digit.web.controllers" , "digit.config"}) +public class Main { + + + public static void main(String[] args) throws Exception { + SpringApplication.run(Main.class, args); + } + +} diff --git a/health-services/census-service/src/main/java/digit/config/Configuration.java b/health-services/census-service/src/main/java/digit/config/Configuration.java new file mode 100644 index 00000000000..8459885357e --- /dev/null +++ b/health-services/census-service/src/main/java/digit/config/Configuration.java @@ -0,0 +1,86 @@ +package digit.config; + +import lombok.*; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Data +@Import({TracerConfiguration.class}) +@NoArgsConstructor +@AllArgsConstructor +@Setter +@Getter +public class Configuration { + + // Allowed roles for census + @Value("#{${allowed.census.roles}}") + private List allowedCensusRoles; + + @Value("#{${workflow.restricted.roles}}") + private List workflowRestrictedRoles; + + // Persister Topic + @Value("${census.create.topic}") + private String censusCreateTopic; + + @Value("${census.update.topic}") + private String censusUpdateTopic; + + @Value("${census.bulk.update.topic}") + private String censusBulkUpdateTopic; + + @Value("${plan.facility.update.topic}") + private String planFcailityUpdateTopic; + + // Boundary Service + @Value("${egov.boundary.service.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.relationship.search.endpoint}") + private String boundaryRelationshipSearchEndpoint; + + @Value("${egov.boundary.hierarchy.search.endpoint}") + private String boundaryHierarchySearchEndpoint; + + // Plan Service + @Value("${egov.plan.service.host}") + private String planServiceHost; + + @Value("${egov.plan.employee.assignment.search.endpoint}") + private String planEmployeeAssignmentSearchEndpoint; + + //Workflow + @Value("${egov.workflow.host}") + private String wfHost; + + @Value("${egov.workflow.transition.path}") + private String wfTransitionPath; + + @Value("${egov.business.service.search.endpoint}") + private String businessServiceSearchEndpoint; + + @Value("${workflow.initiate.action}") + private List wfInitiateActions; + + @Value("${workflow.intermediate.action}") + private List wfIntermediateActions; + + @Value("${workflow.send.back.actions}") + private List wfSendBackActions; + + //SMSNotification + @Value("${egov.sms.notification.topic}") + private String smsNotificationTopic; + + //Pagination + @Value("${census.default.offset}") + private Integer defaultOffset; + + @Value("${census.default.limit}") + private Integer defaultLimit; +} diff --git a/health-services/census-service/src/main/java/digit/config/MainConfiguration.java b/health-services/census-service/src/main/java/digit/config/MainConfiguration.java new file mode 100644 index 00000000000..239331c9cd8 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/config/MainConfiguration.java @@ -0,0 +1,41 @@ +package digit.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import java.util.TimeZone; + +import jakarta.annotation.PostConstruct; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.tracer.config.TracerConfiguration; + + +@Import({TracerConfiguration.class}) +public class MainConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Autowired + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/config/ServiceConstants.java b/health-services/census-service/src/main/java/digit/config/ServiceConstants.java new file mode 100644 index 00000000000..5d944060848 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/config/ServiceConstants.java @@ -0,0 +1,114 @@ +package digit.config; + + +import org.springframework.stereotype.Component; + + +@Component +public class ServiceConstants { + + public static final String EXTERNAL_SERVICE_EXCEPTION = "External Service threw an Exception: "; + public static final String SEARCHER_SERVICE_EXCEPTION = "Exception while fetching from searcher: "; + + public static final String IDGEN_ERROR = "IDGEN ERROR"; + public static final String NO_IDS_FOUND_ERROR = "No ids returned from idgen Service"; + + public static final String ERROR_WHILE_FETCHING_FROM_MDMS = "Exception occurred while fetching category lists from mdms: "; + + public static final String ERROR_WHILE_FETCHING_BOUNDARY_DETAILS = "Exception occurred while fetching boundary relationship from boundary service: "; + + public static final String ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS = "Exception occurred while fetching boundary hierarchy details from boundary service: "; + + public static final String ERROR_WHILE_FETCHING_EMPLOYEE_ASSIGNMENT_DETAILS = "Exception occurred while fetching plan employee assignment details from plan service: "; + + public static final String ERROR_WHILE_FETCHING_BUSINESS_SERVICE_DETAILS = "Exception occurred while fetching business service details: "; + + public static final String RES_MSG_ID = "uief87324"; + public static final String SUCCESSFUL = "successful"; + public static final String FAILED = "failed"; + + public static final String URL = "url"; + public static final String URL_SHORTENING_ERROR_CODE = "URL_SHORTENING_ERROR"; + public static final String URL_SHORTENING_ERROR_MESSAGE = "Unable to shorten url: "; + + public static final String DOB_FORMAT_Y_M_D = "yyyy-MM-dd"; + public static final String DOB_FORMAT_D_M_Y = "dd/MM/yyyy"; + public static final String ILLEGAL_ARGUMENT_EXCEPTION_CODE = "IllegalArgumentException"; + public static final String OBJECTMAPPER_UNABLE_TO_CONVERT = "ObjectMapper not able to convertValue in userCall"; + public static final String DOB_FORMAT_D_M_Y_H_M_S = "dd-MM-yyyy HH:mm:ss"; + public static final String CREATED_DATE = "createdDate"; + public static final String LAST_MODIFIED_DATE = "lastModifiedDate"; + public static final String DOB = "dob"; + public static final String PWD_EXPIRY_DATE = "pwdExpiryDate"; + public static final String INVALID_DATE_FORMAT_CODE = "INVALID_DATE_FORMAT"; + public static final String INVALID_DATE_FORMAT_MESSAGE = "Failed to parse date format in user"; + public static final String CITIZEN_UPPER = "CITIZEN"; + public static final String CITIZEN_LOWER = "Citizen"; + public static final String USER = "user"; + public static final String PIPE_REGEX = "\\|"; + public static final String FACILITY_ID_FIELD = "facilityId"; + public static final String FACILITY_NAME_FIELD = "facilityName"; + + public static final String PARSING_ERROR_CODE = "PARSING ERROR"; + public static final String PARSING_ERROR_MESSAGE = "Failed to parse JSON data from PGobject"; + + public static final String FAILED_TO_PARSE_BUSINESS_SERVICE_SEARCH = "Failed to parse response of workflow business service search"; + public static final String BUSINESS_SERVICE_NOT_FOUND = "BUSINESSSERVICE_NOT_FOUND"; + public static final String THE_BUSINESS_SERVICE = "The businessService "; + public static final String NOT_FOUND = " is not found"; + public static final String TENANTID = "?tenantId="; + public static final String BUSINESS_SERVICES = "&businessServices="; + + public static final String NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE = "NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE"; + public static final String NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE = "Invalid or incorrect boundaryCode. No boundary data found."; + + public static final String NO_BUSINESS_SERVICE_DATA_FOUND_CODE = "NO_BUSINESS_SERVICE_DATA_FOUND"; + public static final String NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE = "Invalid or incorrect businessService. No business service data found."; + + public static final String USERINFO_MISSING_CODE = "USERINFO_MISSING"; + public static final String USERINFO_MISSING_MESSAGE = "UserInfo is missing in Request Info "; + + public static final String ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE = "ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS"; + public static final String ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE = "Exception occurred while updating additional details : "; + + public static final String WORKFLOW_INTEGRATION_ERROR_CODE = "WORKFLOW_INTEGRATION_ERROR"; + public static final String WORKFLOW_INTEGRATION_ERROR_MESSAGE = "Exception occured while integrating with workflow : "; + + public static final String INVALID_PARTNER_CODE = "INVALID_PARTNER"; + public static final String INVALID_PARTNER_MESSAGE = "Invalid partner assignment or invalid jurisdiction of the assigned partner"; + + public static final String INVALID_CENSUS_CODE = "INVALID_CENSUS"; + public static final String INVALID_CENSUS_MESSAGE = "Provided census does not exist"; + + public static final String DUPLICATE_CENSUS_ID_IN_BULK_UPDATE_CODE = "DUPLICATE_CENSUS_ID_IN_BULK_UPDATE"; + public static final String DUPLICATE_CENSUS_ID_IN_BULK_UPDATE_MESSAGE = "Census provided in the bulk update request are not unique."; + + public static final String INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE_CODE = "INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE"; + public static final String INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE_MESSAGE = "Tenant id and source should be same across all entries for bulk update."; + + public static final String WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE_CODE = "WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE"; + public static final String WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE_MESSAGE = "Workflow information is mandatory for each entry for bulk update"; + + public static final String DUPLICATE_KEY_IN_ADDITIONAL_FIELD_CODE = "DUPLICATE_KEY_IN_ADDITIONAL_FIELD"; + public static final String DUPLICATE_KEY_IN_ADDITIONAL_FIELD_MESSGAE = "Duplicate key found in additional field : "; + + public static final String CENSUS_ALREADY_EXISTS_CODE = "CENSUS_ALREADY_EXISTS"; + public static final String CENSUS_ALREADY_EXISTS_MESSAGE = "Census with the given boundary and source already exists."; + + public static final String DIFFERENT_WORKFLOW_FOR_BULK_UPDATE_CODE = "DIFFERENT_WORKFLOW_FOR_BULK_UPDATE"; + public static final String DIFFERENT_WORKFLOW_FOR_BULK_UPDATE_MESSAGE = "All entries should be in the same state for bulk transitioning census records."; + + public static final String UNAUTHORIZED_WORKFLOW_ACCESS_CODE = "UNAUTHORIZED_WORKFLOW_ACCESS"; + public static final String UNAUTHORIZED_WORKFLOW_ACCESS_MESSAGE = "User with provided roles cannot have an active workflow. Please remove the workflow or update user roles."; + + public static final String SEARCH_CRITERIA_EMPTY_CODE = "SEARCH_CRITERIA_EMPTY"; + public static final String SEARCH_CRITERIA_EMPTY_MESSAGE = "Search criteria cannot be empty"; + + public static final String TENANT_ID_EMPTY_CODE = "TENANT_ID_EMPTY"; + public static final String TENANT_ID_EMPTY_MESSAGE = "Tenant Id cannot be empty, TenantId should be present"; + + //Workflow constants + public static final String MODULE_NAME_VALUE = "census-service"; + + public static final String CENSUS_BUSINESS_SERVICE = "CENSUS"; +} diff --git a/health-services/census-service/src/main/java/digit/kafka/FacilityCatchmentConsumer.java b/health-services/census-service/src/main/java/digit/kafka/FacilityCatchmentConsumer.java new file mode 100644 index 00000000000..d5be4b7458c --- /dev/null +++ b/health-services/census-service/src/main/java/digit/kafka/FacilityCatchmentConsumer.java @@ -0,0 +1,99 @@ +package digit.kafka; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.repository.CensusRepository; +import digit.service.CensusService; +import digit.service.enrichment.CensusEnrichment; +import digit.util.BoundaryUtil; +import digit.util.CommonUtil; +import digit.web.models.BulkCensusRequest; +import digit.web.models.Census; +import digit.web.models.CensusResponse; +import digit.web.models.boundary.BoundaryTypeHierarchyResponse; +import digit.web.models.plan.PlanFacilityDTO; +import digit.web.models.plan.PlanFacilityRequestDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static digit.config.ServiceConstants.FACILITY_ID_FIELD; +import static digit.config.ServiceConstants.FACILITY_NAME_FIELD; + +@Component +@Slf4j +public class FacilityCatchmentConsumer { + + private ObjectMapper objectMapper; + + private CensusService service; + + private CensusRepository repository; + + private CommonUtil commonUtil; + + private BoundaryUtil boundaryUtil; + + private CensusEnrichment enrichment; + + public FacilityCatchmentConsumer(ObjectMapper objectMapper, CensusService service, CommonUtil commonUtil, CensusRepository repository, BoundaryUtil boundaryUtil, CensusEnrichment enrichment) { + this.objectMapper = objectMapper; + this.service = service; + this.commonUtil = commonUtil; + this.repository = repository; + this.boundaryUtil = boundaryUtil; + this.enrichment = enrichment; + } + + @KafkaListener(topics = {"${plan.facility.update.topic}"}) + public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + PlanFacilityRequestDTO planFacilityRequestDTO = objectMapper.convertValue(consumerRecord, PlanFacilityRequestDTO.class); + PlanFacilityDTO planFacilityDTO = planFacilityRequestDTO.getPlanFacilityDTO(); + + CensusResponse censusResponse = service.search(commonUtil.getCensusSearchRequest(planFacilityDTO.getTenantId(), planFacilityDTO.getPlanConfigurationId(), planFacilityDTO.getServiceBoundaries(), planFacilityDTO.getInitiallySetServiceBoundaries(), planFacilityRequestDTO.getRequestInfo())); + List censusFromSearch = censusResponse.getCensus(); + + BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(planFacilityRequestDTO.getRequestInfo(), censusFromSearch.get(0).getTenantId(), censusFromSearch.get(0).getHierarchyType()); + String facilityId = planFacilityRequestDTO.getPlanFacilityDTO().getFacilityId(); + String facilityName = planFacilityRequestDTO.getPlanFacilityDTO().getFacilityName(); + + Set boundariesWithFacility = new HashSet<>(List.of(planFacilityDTO.getServiceBoundaries().split(","))); + Set boundariesWithNoFacility = new HashSet<>(planFacilityDTO.getInitiallySetServiceBoundaries()); + + censusFromSearch.forEach(census -> { + String boundaryCode = census.getBoundaryCode(); + + if (!boundariesWithFacility.contains(boundaryCode)) { + + // Unassigning facilities to the boundaries which were initially assigned that facility + census.setAdditionalDetails(commonUtil.removeFieldFromAdditionalDetails(census.getAdditionalDetails(), FACILITY_ID_FIELD)); + census.setAdditionalDetails(commonUtil.removeFieldFromAdditionalDetails(census.getAdditionalDetails(), FACILITY_NAME_FIELD)); + census.setFacilityAssigned(Boolean.FALSE); + census.setPartnerAssignmentValidationEnabled(Boolean.FALSE); + + } else if (!boundariesWithNoFacility.contains(boundaryCode)) { + + // Assigning facilities to the newly added boundaries in the update request. + census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), FACILITY_ID_FIELD, facilityId)); + census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), FACILITY_NAME_FIELD, facilityName)); + census.setFacilityAssigned(Boolean.TRUE); + census.setPartnerAssignmentValidationEnabled(Boolean.FALSE); + } + }); + + // Enrich jurisdiction mapping in census for indexer + enrichment.enrichJurisdictionMapping(censusFromSearch, boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0)); + repository.bulkUpdate(BulkCensusRequest.builder().requestInfo(planFacilityRequestDTO.getRequestInfo()).census(censusFromSearch).build()); + + } catch (Exception exception) { + log.error("Error in census consumer", exception); + } + } +} diff --git a/health-services/census-service/src/main/java/digit/kafka/Producer.java b/health-services/census-service/src/main/java/digit/kafka/Producer.java new file mode 100644 index 00000000000..542f4f686c0 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/kafka/Producer.java @@ -0,0 +1,20 @@ +package digit.kafka; + +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.kafka.CustomKafkaTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +// NOTE: If tracer is disabled change CustomKafkaTemplate to KafkaTemplate in autowiring + +@Service +@Slf4j +public class Producer { + + @Autowired + private CustomKafkaTemplate kafkaTemplate; + + public void push(String topic, Object value) { + kafkaTemplate.send(topic, value); + } +} diff --git a/health-services/census-service/src/main/java/digit/kafka/ResourceCensusConsumer.java b/health-services/census-service/src/main/java/digit/kafka/ResourceCensusConsumer.java new file mode 100644 index 00000000000..e161225b23a --- /dev/null +++ b/health-services/census-service/src/main/java/digit/kafka/ResourceCensusConsumer.java @@ -0,0 +1,37 @@ +package digit.kafka; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.service.CensusService; +import digit.web.models.CensusRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@Slf4j +public class ResourceCensusConsumer { + + private CensusService censusService; + + private ObjectMapper mapper; + + public ResourceCensusConsumer(CensusService censusService, ObjectMapper mapper) { + this.censusService = censusService; + this.mapper = mapper; + } + + @KafkaListener(topics = {"${resource.config.consumer.census.create.topic}"}) + public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + CensusRequest censusRequest = mapper.convertValue(consumerRecord, CensusRequest.class); + censusRequest.getCensus().setPartnerAssignmentValidationEnabled(Boolean.FALSE); + censusService.create(censusRequest); + } catch (Exception exception) { + log.error("Error in resource census consumer", exception); + } + } +} diff --git a/health-services/census-service/src/main/java/digit/repository/CensusRepository.java b/health-services/census-service/src/main/java/digit/repository/CensusRepository.java new file mode 100644 index 00000000000..4a9f159e7e9 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/CensusRepository.java @@ -0,0 +1,21 @@ +package digit.repository; + +import digit.web.models.*; + +import java.util.List; +import java.util.Map; + +public interface CensusRepository { + + public void create(CensusRequest censusRequest); + + public List search(CensusSearchCriteria censusSearchCriteria); + + public void update(CensusRequest censusRequest); + + public void bulkUpdate(BulkCensusRequest request); + + public Integer count(CensusSearchCriteria censusSearchCriteria); + + public Map statusCount(CensusSearchRequest censusSearchRequest); +} diff --git a/health-services/census-service/src/main/java/digit/repository/ServiceRequestRepository.java b/health-services/census-service/src/main/java/digit/repository/ServiceRequestRepository.java new file mode 100644 index 00000000000..d09d230e4fa --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/ServiceRequestRepository.java @@ -0,0 +1,45 @@ +package digit.repository; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.ServiceCallException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +import static digit.config.ServiceConstants.*; + +@Repository +@Slf4j +public class ServiceRequestRepository { + + private ObjectMapper mapper; + + private RestTemplate restTemplate; + + public ServiceRequestRepository(ObjectMapper mapper, RestTemplate restTemplate) { + this.mapper = mapper; + this.restTemplate = restTemplate; + } + + + public Object fetchResult(StringBuilder uri, Object request) { + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + Object response = null; + try { + response = restTemplate.postForObject(uri.toString(), request, Map.class); + } catch (HttpClientErrorException e) { + log.error(EXTERNAL_SERVICE_EXCEPTION, e); + throw new ServiceCallException(e.getResponseBodyAsString()); + } catch (Exception e) { + log.error(SEARCHER_SERVICE_EXCEPTION, e); + } + + return response; + } +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/repository/impl/CensusRepositoryImpl.java b/health-services/census-service/src/main/java/digit/repository/impl/CensusRepositoryImpl.java new file mode 100644 index 00000000000..c6dec4b4d11 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/impl/CensusRepositoryImpl.java @@ -0,0 +1,219 @@ +package digit.repository.impl; + +import digit.config.Configuration; +import digit.kafka.Producer; +import digit.repository.CensusRepository; +import digit.repository.querybuilder.CensusQueryBuilder; +import digit.repository.rowmapper.CensusRowMapper; +import digit.repository.rowmapper.StatusCountRowMapper; +import digit.util.CommonUtil; +import digit.web.models.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.SingleColumnRowMapper; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static digit.config.ServiceConstants.CENSUS_BUSINESS_SERVICE; + +@Slf4j +@Repository +public class CensusRepositoryImpl implements CensusRepository { + + private Producer producer; + + private Configuration config; + + private CensusQueryBuilder queryBuilder; + + private CensusRowMapper censusRowMapper; + + private JdbcTemplate jdbcTemplate; + + private StatusCountRowMapper statusCountRowMapper; + + private CommonUtil commonUtil; + + public CensusRepositoryImpl(Producer producer, Configuration config, CensusQueryBuilder queryBuilder, CensusRowMapper censusRowMapper, JdbcTemplate jdbcTemplate, StatusCountRowMapper statusCountRowMapper,CommonUtil commonUtil) { + this.producer = producer; + this.config = config; + this.queryBuilder = queryBuilder; + this.censusRowMapper = censusRowMapper; + this.jdbcTemplate = jdbcTemplate; + this.statusCountRowMapper = statusCountRowMapper; + this.commonUtil = commonUtil; + } + + /** + * Pushes a new census record to persister kafka topic. + * + * @param censusRequest The request containing the census details + */ + @Override + public void create(CensusRequest censusRequest) { + CensusRequestDTO requestDTO = convertToReqDTO(censusRequest); + producer.push(config.getCensusCreateTopic(), requestDTO); + } + + /** + * Searches for census records based on the provided search criteria. + * + * @param censusSearchCriteria The criteria to use for searching census records. + * @return A list of census records that match the search criteria. + */ + @Override + public List search(CensusSearchCriteria censusSearchCriteria) { + + if(censusSearchCriteria.getAreaCodes() != null && censusSearchCriteria.getAreaCodes().isEmpty()) + return new ArrayList<>(); + + // Fetch census ids from database + List censusIds = queryDatabaseForCensusIds(censusSearchCriteria); + + // Return empty list back as response if no census ids are found + if(CollectionUtils.isEmpty(censusIds)) { + log.info("No census ids found for provided census search criteria."); + return new ArrayList<>(); + } + + // Fetch census from database based on the acquired ids + return searchCensusByIds(censusIds); + } + + private List searchCensusByIds(List censusIds) { + + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getCensusQuery(censusIds, preparedStmtList); + log.info("Census query: " + query); + return jdbcTemplate.query(query, censusRowMapper, preparedStmtList.toArray()); + + } + + private List queryDatabaseForCensusIds(CensusSearchCriteria censusSearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getCensusSearchQuery(censusSearchCriteria, preparedStmtList); + log.info("Census search query: " + query); + return jdbcTemplate.query(query, new SingleColumnRowMapper<>(String.class), preparedStmtList.toArray()); + } + + /** + * Counts the number of census records based on the provided search criteria. + * + * @param censusSearchCriteria The search criteria for filtering census records. + * @return The total count of census matching the search criteria. + */ + @Override + public Integer count(CensusSearchCriteria censusSearchCriteria) { + + if(censusSearchCriteria.getAreaCodes() != null && censusSearchCriteria.getAreaCodes().isEmpty()) + return 0; + + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getCensusCountQuery(censusSearchCriteria, preparedStmtList); + + return jdbcTemplate.queryForObject(query, preparedStmtList.toArray(), Integer.class); + } + + /** + * Counts the census record based on their current status for the provided search criteria. + * + * @param censusSearchRequest The request with search criteria for filtering census records. + * @return The status count of census records for the given search criteria. + */ + @Override + public Map statusCount(CensusSearchRequest censusSearchRequest) { + List preparedStmtList = new ArrayList<>(); + List statusList = commonUtil.getStatusFromBusinessService(censusSearchRequest.getRequestInfo(), CENSUS_BUSINESS_SERVICE, censusSearchRequest.getCensusSearchCriteria().getTenantId()); + + String query = queryBuilder.getCensusStatusCountQuery(censusSearchRequest.getCensusSearchCriteria(), preparedStmtList); + Map statusCountMap = jdbcTemplate.query(query, statusCountRowMapper, preparedStmtList.toArray()); + + statusList.forEach(status -> { + if(ObjectUtils.isEmpty(statusCountMap.get(status))) + statusCountMap.put(status, 0); + }); + + return statusCountMap; + } + + /** + * Pushes an updated existing census record to persister kafka topic. + * + * @param censusRequest The request containing the updated census details + */ + @Override + public void update(CensusRequest censusRequest) { + CensusRequestDTO requestDTO = convertToReqDTO(censusRequest); + producer.push(config.getCensusUpdateTopic(), requestDTO); + } + + /** + * Updates workflow status of a list of census records. + * + * @param request The bulk request containing the census records. + */ + @Override + public void bulkUpdate(BulkCensusRequest request) { + // Get bulk census update query + String bulkCensusUpdateQuery = queryBuilder.getBulkCensusQuery(); + + // Prepare rows for bulk update + List rows = request.getCensus().stream().map(census -> new Object[] { + census.getStatus(), + !CollectionUtils.isEmpty(census.getAssignee()) ? String.join(",", census.getAssignee()) : census.getAssignee(), + census.getAuditDetails().getLastModifiedBy(), + census.getAuditDetails().getLastModifiedTime(), + commonUtil.convertToPgObject(census.getAdditionalDetails()), + census.getFacilityAssigned(), + census.getId() + }).toList(); + + // Perform bulk update + jdbcTemplate.batchUpdate(bulkCensusUpdateQuery, rows); + producer.push(config.getCensusBulkUpdateTopic(), request); + } + + /** + * Converts the CensusRequest to a data transfer object (DTO) + * + * @param censusRequest The request to be converted to DTO + * @return a DTO for CensusRequest + */ + private CensusRequestDTO convertToReqDTO(CensusRequest censusRequest) { + Census census = censusRequest.getCensus(); + + String assignee = !CollectionUtils.isEmpty(census.getAssignee()) ? String.join(",", census.getAssignee()) : null; + + // Creating a new data transfer object (DTO) for Census + CensusDTO censusDTO = CensusDTO.builder() + .id(census.getId()) + .tenantId(census.getTenantId()) + .hierarchyType(census.getHierarchyType()) + .boundaryCode(census.getBoundaryCode()) + .assignee(assignee) + .status(census.getStatus()) + .type(census.getType().toString()) + .totalPopulation(census.getTotalPopulation()) + .populationByDemographics(census.getPopulationByDemographics()) + .jurisdictionMapping(census.getJurisdictionMapping()) + .additionalFields(census.getAdditionalFields()) + .effectiveFrom(census.getEffectiveFrom()) + .effectiveTo(census.getEffectiveTo()) + .source(census.getSource()) + .boundaryAncestralPath(census.getBoundaryAncestralPath().get(0)) + .facilityAssigned(census.getFacilityAssigned()) + .additionalDetails(census.getAdditionalDetails()) + .auditDetails(census.getAuditDetails()) + .build(); + + return CensusRequestDTO.builder() + .requestInfo(censusRequest.getRequestInfo()) + .censusDTO(censusDTO) + .build(); + } +} diff --git a/health-services/census-service/src/main/java/digit/repository/querybuilder/CensusQueryBuilder.java b/health-services/census-service/src/main/java/digit/repository/querybuilder/CensusQueryBuilder.java new file mode 100644 index 00000000000..7eec3f639ca --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/querybuilder/CensusQueryBuilder.java @@ -0,0 +1,219 @@ +package digit.repository.querybuilder; + +import digit.config.Configuration; +import digit.util.QueryUtil; +import digit.web.models.CensusSearchCriteria; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; + +@Component +public class CensusQueryBuilder { + + private QueryUtil queryUtil; + + private Configuration config; + + public CensusQueryBuilder(QueryUtil queryUtil, Configuration config) { + this.config = config; + this.queryUtil = queryUtil; + } + + private static final String CENSUS_SEARCH_BASE_QUERY = "SELECT id FROM census cen"; + + private static final String CENSUS_QUERY = "SELECT cen.id as census_id, cen.tenant_id as census_tenant_id, cen.hierarchy_type as census_hierarchy_type, cen.boundary_code as census_boundary_code, cen.type as census_type, cen.total_population as census_total_population, cen.effective_from as census_effective_from, cen.effective_to as census_effective_to, cen.source as census_source, cen.status as census_status, cen.assignee as census_assignee, cen.boundary_ancestral_path as census_boundary_ancestral_path, cen.facility_assigned as census_facility_assigned, cen.additional_details as census_additional_details, cen.created_by as census_created_by, cen.created_time as census_created_time, cen.last_modified_by as census_last_modified_by, cen.last_modified_time as census_last_modified_time, \n" + + "\t pbd.id as population_by_demographics_id, pbd.census_id as population_by_demographics_census_id, pbd.demographic_variable as population_by_demographics_demographic_variable, pbd.population_distribution as population_by_demographics_population_distribution, pbd.created_by as population_by_demographics_created_by, pbd.created_time as population_by_demographics_created_time, pbd.last_modified_by as population_by_demographics_last_modified_by, pbd.last_modified_time as population_by_demographics_last_modified_time, \n" + + "\t adf.id as additional_field_id, adf.census_id as additional_field_census_id, adf.key as additional_field_key, adf.value as additional_field_value, adf.show_on_ui as additional_field_show_on_ui, adf.editable as additional_field_editable, adf.order as additional_field_order \n" + + "\t FROM census cen \n" + + "\t LEFT JOIN population_by_demographics pbd ON cen.id = pbd.census_id \n" + + "\t LEFT JOIN additional_field adf ON cen.id = adf.census_id"; + + private static final String CENSUS_SEARCH_QUERY_ORDER_BY_CLAUSE = " ORDER BY cen.last_modified_time DESC"; + + private static final String CENSUS_SEARCH_QUERY_COUNT_WRAPPER = "SELECT COUNT(id) AS total_count FROM ( "; + + private static final String CENSUS_STATUS_COUNT_QUERY = "SELECT COUNT(id) as census_status_count, status as census_status FROM (SELECT id, status FROM census {INTERNAL_QUERY}) as census_status_map GROUP BY census_status"; + + private static final String BULK_CENSUS_UPDATE_QUERY = "UPDATE census SET status = ?, assignee = ?, last_modified_by = ?, last_modified_time = ?, additional_details = ?, facility_assigned = ? WHERE id = ?"; + + /** + * Constructs a SQL query string for searching Census records based on the provided search criteria. + * Also adds an ORDER BY clause and handles pagination. + * + * @param ids The census ids used for filtering Census records. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A complete SQL query string for searching Census records. + */ + public String getCensusQuery(List ids, List preparedStmtList) { + String query = buildCensusQuery(ids, preparedStmtList); + query = queryUtil.addOrderByClause(query, CENSUS_SEARCH_QUERY_ORDER_BY_CLAUSE); + return query; + } + + private String buildCensusQuery(List ids, List preparedStmtList) { + StringBuilder builder = new StringBuilder(CENSUS_QUERY); + + if (!CollectionUtils.isEmpty(ids)) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" cen.id IN ( ").append(queryUtil.createQuery(ids.size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, ids); + } + + return builder.toString(); + } + + public String getCensusSearchQuery(CensusSearchCriteria censusSearchCriteria, List preparedStmtList) { + String query = buildCensusSearchQuery(censusSearchCriteria, preparedStmtList, Boolean.FALSE, Boolean.FALSE); + query = queryUtil.addOrderByClause(query, CENSUS_SEARCH_QUERY_ORDER_BY_CLAUSE); + query = getPaginatedQuery(query, preparedStmtList, censusSearchCriteria); + return query; + } + + /** + * Constructs the count query to get the total count of census based on search criteria. + * + * @param searchCriteria The criteria used for filtering Census records. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A SQL query string to get the total count of Census records for a given search criteria. + */ + public String getCensusCountQuery(CensusSearchCriteria searchCriteria, List preparedStmtList) { + return buildCensusSearchQuery(searchCriteria, preparedStmtList, Boolean.TRUE, Boolean.FALSE); + } + + /** + * Constructs the status count query to get the count of census based on their current status for the given search criteria + * + * @param searchCriteria The criteria used for filtering Census records. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A SQL query string to get the status count of Census records for a given search criteria. + */ + public String getCensusStatusCountQuery(CensusSearchCriteria searchCriteria, List preparedStmtList) { + CensusSearchCriteria censusSearchCriteria = CensusSearchCriteria.builder().tenantId(searchCriteria.getTenantId()).source(searchCriteria.getSource()).jurisdiction(searchCriteria.getJurisdiction()).build(); + return buildCensusSearchQuery(censusSearchCriteria, preparedStmtList, Boolean.FALSE, Boolean.TRUE); + } + + /** + * Constructs query based on the provided search criteria + * + * @param criteria The criteria used for filtering Census ids. + * @param preparedStmtList A list to store prepared statement parameters. + * @return SQL query string for searching Census ids based on search criteria + */ + private String buildCensusSearchQuery(CensusSearchCriteria criteria, List preparedStmtList, Boolean isCount, Boolean isStatusCount) { + StringBuilder builder = new StringBuilder(CENSUS_SEARCH_BASE_QUERY); + + if(isStatusCount) { + builder = new StringBuilder(); + } + + if (!ObjectUtils.isEmpty(criteria.getId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" id = ?"); + preparedStmtList.add(criteria.getId()); + } + + if (!CollectionUtils.isEmpty(criteria.getIds())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" id IN ( ").append(queryUtil.createQuery(criteria.getIds().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, criteria.getIds()); + } + + if (!ObjectUtils.isEmpty(criteria.getTenantId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" tenant_id = ?"); + preparedStmtList.add(criteria.getTenantId()); + } + + if (!ObjectUtils.isEmpty(criteria.getStatus())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" status = ?"); + preparedStmtList.add(criteria.getStatus()); + } + + if (!ObjectUtils.isEmpty(criteria.getSource())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" source = ?"); + preparedStmtList.add(criteria.getSource()); + } + + if (!ObjectUtils.isEmpty(criteria.getFacilityAssigned())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" facility_assigned = ?"); + preparedStmtList.add(criteria.getFacilityAssigned()); + } + + if (!ObjectUtils.isEmpty(criteria.getEffectiveTo())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + if (criteria.getEffectiveTo() == 0) { + builder.append(" effective_to IS NULL "); + } else { + builder.append(" effective_to = ?"); + preparedStmtList.add(criteria.getEffectiveTo()); + } + } + + if (!CollectionUtils.isEmpty(criteria.getAreaCodes())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" boundary_code IN ( ").append(queryUtil.createQuery(criteria.getAreaCodes().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, criteria.getAreaCodes()); + } + + if (!ObjectUtils.isEmpty(criteria.getAssignee())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ").append(queryUtil.createQuery(Collections.singleton(criteria.getAssignee()).size())).append(" ]").append("::text[] "); + builder.append(" && string_to_array(assignee, ',') "); + queryUtil.addToPreparedStatement(preparedStmtList, Collections.singleton(criteria.getAssignee())); + } + + if (!CollectionUtils.isEmpty(criteria.getJurisdiction())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ").append(queryUtil.createQuery(criteria.getJurisdiction().size())).append(" ]").append("::text[] "); + builder.append(" && string_to_array(boundary_ancestral_path, '|') "); + queryUtil.addToPreparedStatement(preparedStmtList, criteria.getJurisdiction()); + } + + StringBuilder countQuery = new StringBuilder(); + if (isCount) { + countQuery.append(CENSUS_SEARCH_QUERY_COUNT_WRAPPER).append(builder); + countQuery.append(") AS subquery"); + + return countQuery.toString(); + } + + if (isStatusCount) { + return CENSUS_STATUS_COUNT_QUERY.replace("{INTERNAL_QUERY}", builder); + } + + return builder.toString(); + } + + public String getBulkCensusQuery() { + return BULK_CENSUS_UPDATE_QUERY; + } + + /** + * This method appends pagination i.e. limit and offset to the query. + * + * @param query the query to which pagination is to be added. + * @param preparedStmtList prepared statement list to add limit and offset. + * @return a query with pagination + */ + public String getPaginatedQuery(String query, List preparedStmtList, CensusSearchCriteria searchCriteria) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(!ObjectUtils.isEmpty(searchCriteria.getOffset()) ? searchCriteria.getOffset() : config.getDefaultOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(!ObjectUtils.isEmpty(searchCriteria.getLimit()) ? searchCriteria.getLimit() : config.getDefaultLimit()); + + return paginatedQuery.toString(); + } +} diff --git a/health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java b/health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java new file mode 100644 index 00000000000..7edac5005dd --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java @@ -0,0 +1,148 @@ +package digit.repository.rowmapper; + +import digit.util.QueryUtil; +import digit.web.models.AdditionalField; +import digit.web.models.Census; +import digit.web.models.PopulationByDemographic; +import org.egov.common.contract.models.AuditDetails; +import org.postgresql.util.PGobject; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +@Component +public class CensusRowMapper implements ResultSetExtractor> { + + private QueryUtil queryUtil; + + public CensusRowMapper(QueryUtil queryUtil) { + this.queryUtil = queryUtil; + } + + /** + * Creates a list of Census record based on the ResultSet. + * + * @param rs the ResultSet containing data. + * @return a list of Census record + * @throws SQLException + * @throws DataAccessException + */ + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map censusMap = new LinkedHashMap<>(); + Set populationByDemographicSet = new HashSet<>(); + Set additionalFieldSet = new HashSet<>(); + + while (rs.next()) { + String censusId = rs.getString("census_id"); + Census censusEntry = censusMap.get(censusId); + + if (ObjectUtils.isEmpty(censusEntry)) { + censusEntry = new Census(); + populationByDemographicSet.clear(); + additionalFieldSet.clear(); + + // Prepare audit details + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("census_created_by")).createdTime(rs.getLong("census_created_time")).lastModifiedBy(rs.getString("census_last_modified_by")).lastModifiedTime(rs.getLong("census_last_modified_time")).build(); + + String commaSeparatedAssignee = rs.getString("census_assignee"); + List assignee = !ObjectUtils.isEmpty(commaSeparatedAssignee) ? Arrays.asList(commaSeparatedAssignee.split(",")) : null; + + // Prepare census entry + censusEntry.setId(rs.getString("census_id")); + censusEntry.setTenantId(rs.getString("census_tenant_id")); + censusEntry.setHierarchyType(rs.getString("census_hierarchy_type")); + censusEntry.setBoundaryCode(rs.getString("census_boundary_code")); + censusEntry.setType(Census.TypeEnum.fromValue(rs.getString("census_type"))); + censusEntry.setTotalPopulation(rs.getLong("census_total_population")); + censusEntry.setEffectiveFrom(rs.getLong("census_effective_from")); + censusEntry.setEffectiveTo(rs.getLong("census_effective_to")); + censusEntry.setSource(rs.getString("census_source")); + censusEntry.setStatus(rs.getString("census_status")); + censusEntry.setAssignee(assignee); + censusEntry.setBoundaryAncestralPath(Collections.singletonList(rs.getString("census_boundary_ancestral_path"))); + censusEntry.setFacilityAssigned(rs.getBoolean("census_facility_assigned")); + censusEntry.setAdditionalDetails(queryUtil.parseJson((PGobject) rs.getObject("census_additional_details"))); + censusEntry.setAuditDetails(auditDetails); + } + addPopulationByDemographic(rs, populationByDemographicSet, censusEntry); + addAdditionalField(rs, additionalFieldSet, censusEntry); + + censusMap.put(censusId, censusEntry); + } + + return new ArrayList<>(censusMap.values()); + } + + /** + * Adds a AdditionalField object to the census entry based on the result set. + * + * @param rs The ResultSet containing the data. + * @param additionalFieldSet A set to keep track of added AdditionalField objects. + * @param censusEntry The Census entry to which the AdditionalField object will be added. + * @throws SQLException If an SQL error occurs. + */ + private void addAdditionalField(ResultSet rs, Set additionalFieldSet, Census censusEntry) throws SQLException { + String additionalFieldId = rs.getString("additional_field_id"); + + if (ObjectUtils.isEmpty(additionalFieldId) || additionalFieldSet.contains(additionalFieldId)) { + return; + } + + AdditionalField additionalField = new AdditionalField(); + additionalField.setId(rs.getString("additional_field_id")); + additionalField.setKey(rs.getString("additional_field_key")); + additionalField.setValue(rs.getBigDecimal("additional_field_value")); + additionalField.setShowOnUi(rs.getBoolean("additional_field_show_on_ui")); + additionalField.setEditable(rs.getBoolean("additional_field_editable")); + additionalField.setOrder(rs.getInt("additional_field_order")); + + if (CollectionUtils.isEmpty(censusEntry.getAdditionalFields())) { + List additionalFields = new ArrayList<>(); + additionalFields.add(additionalField); + censusEntry.setAdditionalFields(additionalFields); + } else { + censusEntry.getAdditionalFields().add(additionalField); + } + + additionalFieldSet.add(additionalFieldId); + } + + + /** + * Adds a PopulationByDemographics object to the census entry based on the result set. + * + * @param rs The ResultSet containing the data. + * @param populationByDemographicSet A set to keep track of added PopulationByDemographics objects. + * @param censusEntry The Census entry to which the PopulationByDemographics object will be added. + * @throws SQLException If an SQL error occurs. + */ + private void addPopulationByDemographic(ResultSet rs, Set populationByDemographicSet, Census censusEntry) throws SQLException { + String populationByDemographicId = rs.getString("population_by_demographics_id"); + + if (ObjectUtils.isEmpty(populationByDemographicId) || populationByDemographicSet.contains(populationByDemographicId)) { + return; + } + + PopulationByDemographic populationByDemographic = new PopulationByDemographic(); + populationByDemographic.setId(rs.getString("population_by_demographics_id")); + populationByDemographic.setDemographicVariable(PopulationByDemographic.DemographicVariableEnum.fromValue(rs.getString("population_by_demographics_demographic_variable"))); + populationByDemographic.setPopulationDistribution(queryUtil.parseJson((PGobject) rs.getObject("population_by_demographics_population_distribution"))); + + if (CollectionUtils.isEmpty(censusEntry.getPopulationByDemographics())) { + List populationByDemographicList = new ArrayList<>(); + populationByDemographicList.add(populationByDemographic); + censusEntry.setPopulationByDemographics(populationByDemographicList); + } else { + censusEntry.getPopulationByDemographics().add(populationByDemographic); + } + + populationByDemographicSet.add(populationByDemographicId); + } +} diff --git a/health-services/census-service/src/main/java/digit/repository/rowmapper/StatusCountRowMapper.java b/health-services/census-service/src/main/java/digit/repository/rowmapper/StatusCountRowMapper.java new file mode 100644 index 00000000000..b997f2f933f --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/rowmapper/StatusCountRowMapper.java @@ -0,0 +1,30 @@ +package digit.repository.rowmapper; + +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +@Component +public class StatusCountRowMapper implements ResultSetExtractor> { + + @Override + public Map extractData(ResultSet rs) throws SQLException, DataAccessException { + Map statusCountMap = new HashMap<>(); + + while (rs.next()) { + String status = rs.getString("census_status"); + Integer statusCount = rs.getInt("census_status_count"); + + if(!ObjectUtils.isEmpty(status)) + statusCountMap.put(status, statusCount); + } + + return statusCountMap; + } +} diff --git a/health-services/census-service/src/main/java/digit/service/CensusService.java b/health-services/census-service/src/main/java/digit/service/CensusService.java new file mode 100644 index 00000000000..ec37824bfc1 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/service/CensusService.java @@ -0,0 +1,127 @@ +package digit.service; + +import digit.repository.CensusRepository; +import digit.service.enrichment.CensusEnrichment; +import digit.service.enrichment.CensusTimeframeEnrichment; +import digit.service.validator.CensusValidator; +import digit.service.workflow.WorkflowService; +import digit.util.ResponseInfoFactory; +import digit.web.models.BulkCensusRequest; +import digit.web.models.CensusRequest; +import digit.web.models.CensusResponse; +import digit.web.models.CensusSearchRequest; +import org.springframework.stereotype.Service; + +import java.util.Collections; + +@Service +public class CensusService { + + private ResponseInfoFactory responseInfoFactory; + + private CensusRepository repository; + + private CensusValidator validator; + + private CensusEnrichment enrichment; + + private CensusTimeframeEnrichment timeframeEnrichment; + + private WorkflowService workflow; + + public CensusService(ResponseInfoFactory responseInfoFactory, CensusRepository repository, CensusValidator validator, CensusEnrichment enrichment, CensusTimeframeEnrichment timeframeEnrichment, WorkflowService workflow) { + this.responseInfoFactory = responseInfoFactory; + this.repository = repository; + this.validator = validator; + this.enrichment = enrichment; + this.timeframeEnrichment = timeframeEnrichment; + this.workflow = workflow; + } + + /** + * Creates a new census record based on the provided request. + * + * @param request The request containing the census data. + * @return The created census reponse. + */ + public CensusResponse create(CensusRequest request) { + + // Validate census create request + validator.validateCreate(request); + + // Enrich census create request + enrichment.enrichCreate(request); + + // Enrich timeframe for previous census + timeframeEnrichment.enrichPreviousTimeframe(request); + + // Call workflow transition API for status update + workflow.invokeWorkflowForStatusUpdate(request); + + // Delegate creation request to repository + repository.create(request); + + return CensusResponse.builder() + .census(Collections.singletonList(request.getCensus())) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .build(); + } + + /** + * Searches for census record based on the provided search criteria. + * + * @param request The search request containing the criteria. + * @return A list of census record that matches the search criteria. + */ + public CensusResponse search(CensusSearchRequest request) { + + return CensusResponse.builder() + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .census(repository.search(request.getCensusSearchCriteria())) + .totalCount(repository.count(request.getCensusSearchCriteria())) + .statusCount(repository.statusCount(request)) + .build(); + } + + /** + * Updates an existing census record based on the provided request. + * + * @param request The request containing the updated census data. + * @return The updated census response. + */ + public CensusResponse update(CensusRequest request) { + // Validate census update request + validator.validateUpdate(request); + + // Enrich census update request + enrichment.enrichUpdate(request); + + // Call workflow transition API for status update + workflow.invokeWorkflowForStatusUpdate(request); + + // Delegate update request to repository + repository.update(request); + + return CensusResponse.builder() + .census(Collections.singletonList(request.getCensus())) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .build(); + } + + public CensusResponse bulkUpdate(BulkCensusRequest request) { + + // Validate census bulk update request + validator.validateBulkUpdate(request); + + // Call workflow transition for updating status and assignee + workflow.invokeWorkflowForStatusUpdate(request); + + // Delegate bulk update request to repository + repository.bulkUpdate(request); + + return CensusResponse.builder() + .census(request.getCensus()) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .build(); + } +} diff --git a/health-services/census-service/src/main/java/digit/service/enrichment/CensusEnrichment.java b/health-services/census-service/src/main/java/digit/service/enrichment/CensusEnrichment.java new file mode 100644 index 00000000000..4754de26c4e --- /dev/null +++ b/health-services/census-service/src/main/java/digit/service/enrichment/CensusEnrichment.java @@ -0,0 +1,218 @@ +package digit.service.enrichment; + +import digit.util.CommonUtil; +import digit.web.models.AdditionalField; +import digit.web.models.Census; +import digit.web.models.CensusRequest; +import digit.web.models.boundary.BoundaryTypeHierarchy; +import digit.web.models.boundary.BoundaryTypeHierarchyDefinition; +import digit.web.models.boundary.EnrichedBoundary; +import digit.web.models.boundary.HierarchyRelation; +import org.egov.common.utils.UUIDEnrichmentUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.egov.common.utils.AuditDetailsEnrichmentUtil.prepareAuditDetails; + +@Component +public class CensusEnrichment { + + private CommonUtil commonUtil; + + public CensusEnrichment(CommonUtil commonUtil) { + this.commonUtil = commonUtil; + } + + /** + * Enriches the CensusRequest for creating a new census record. + * Enriches the given census record with generated IDs for Census and PopulationByDemographics. + * Validates user information, enriches audit details and effectiveFrom for create operation. + * + * @param request The CensusRequest to be enriched. + * @throws CustomException if user information is missing in the request. + */ + public void enrichCreate(CensusRequest request) { + Census census = request.getCensus(); + + // Generate id for census record + UUIDEnrichmentUtil.enrichRandomUuid(census, "id"); + + // Generate id for PopulationByDemographics + if (!CollectionUtils.isEmpty(census.getPopulationByDemographics())) { + census.getPopulationByDemographics().forEach(populationByDemographics -> UUIDEnrichmentUtil.enrichRandomUuid(populationByDemographics, "id")); + } + + // Generate id for additionalFields + census.getAdditionalFields().forEach(additionalField -> UUIDEnrichmentUtil.enrichRandomUuid(additionalField, "id")); + + // Set audit details for census record + census.setAuditDetails(prepareAuditDetails(census.getAuditDetails(), request.getRequestInfo(), Boolean.TRUE)); + + // Enrich effectiveFrom for the census record + census.setEffectiveFrom(census.getAuditDetails().getCreatedTime()); + + denormalizeAdditionalFields(request.getCensus()); + } + + private void denormalizeAdditionalFields(Census census) { + Map fieldsToAdd = census.getAdditionalFields().stream() + .collect(Collectors.toMap(AdditionalField::getKey, AdditionalField::getValue)); + + census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), fieldsToAdd)); + } + + /** + * Enriches the boundary ancestral path and jurisdiction mapping for the provided boundary code in the census request. + * + * @param census The census record whose boundary ancestral path has to be enriched. + * @param tenantBoundary boundary relationship from the boundary service for the given boundary code. + */ + public void enrichBoundaryAncestralPath(Census census, HierarchyRelation tenantBoundary) { + EnrichedBoundary boundary = tenantBoundary.getBoundary().get(0); + Map jurisdictionMapping = new LinkedHashMap<>(); + + StringBuilder boundaryAncestralPath = new StringBuilder(boundary.getCode()); + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + + // Iterate through the child boundary until there are no more + while (!CollectionUtils.isEmpty(boundary.getChildren())) { + boundary = boundary.getChildren().get(0); + boundaryAncestralPath.append("|").append(boundary.getCode()); + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + } + + // Setting the boundary ancestral path for the provided boundary + census.setBoundaryAncestralPath(Collections.singletonList(boundaryAncestralPath.toString())); + + // Setting jurisdiction mapping for the provided boundary + census.setJurisdictionMapping(jurisdictionMapping); + } + + /** + * Enriches the CensusRequest for updating an existing census record. + * This method enriches the census record for update, validates user information and enriches audit details for update operation. + * + * @param request The CensusRequest to be enriched. + * @throws CustomException if user information is missing in the request. + */ + public void enrichUpdate(CensusRequest request) { + Census census = request.getCensus(); + + // Generate id for populationByDemographics + if (!CollectionUtils.isEmpty(census.getPopulationByDemographics())) { + census.getPopulationByDemographics().forEach(populationByDemographics -> { + if (ObjectUtils.isEmpty(populationByDemographics.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(populationByDemographics, "id"); + } + }); + } + + //Generate id for additionalFields + census.getAdditionalFields().forEach(additionalField -> { + if (ObjectUtils.isEmpty(additionalField.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(additionalField, "id"); + } + }); + + // Set last modified time on update call + census.getAuditDetails().setLastModifiedTime(System.currentTimeMillis()); + + denormalizeAdditionalFields(request.getCensus()); + } + + /** + * Helper method to enrich boundary hierarchy mapping. + * Creates a mapping of parentBoundaryType to childBoundaryType from the boundaryTypeHierarchy search response. + * + * @param boundaryTypeHierarchyDef Search response from boundary hierarchy search. + * @param boundaryHierarchyMapping boundary hierarchy map to be enriched. + * @return returns the highest boundary hierarchy for the given hierarchy type. + */ + private String getBoundaryHierarchyMapping(BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef, Map boundaryHierarchyMapping) { + String highestBoundaryHierarchy = null; + + for (BoundaryTypeHierarchy boundaryTypeHierarchy : boundaryTypeHierarchyDef.getBoundaryHierarchy()) { + if (ObjectUtils.isEmpty(boundaryTypeHierarchy.getParentBoundaryType())) + highestBoundaryHierarchy = boundaryTypeHierarchy.getBoundaryType(); + else + boundaryHierarchyMapping.put(boundaryTypeHierarchy.getParentBoundaryType(), boundaryTypeHierarchy.getBoundaryType()); + } + + return highestBoundaryHierarchy; + } + + /** + * Enriches jurisdiction mapping in census for the given boundary ancestral path. + * + * @param census census data with boundary ancestral path. + * @param boundaryTypeHierarchyDef boundary hierarchy for the given hierarchy type. + */ + public void enrichJurisdictionMapping(Census census, BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef) { + Map boundaryHierarchyMapping = new HashMap<>(); + + // Enriches the boundaryHierarchyMapping and returns the highest boundary hierarchy for the given hierarchy type. + String highestBoundaryHierarchy = getBoundaryHierarchyMapping(boundaryTypeHierarchyDef, boundaryHierarchyMapping); + + Map jurisdictionMapping = new LinkedHashMap<>(); + String boundaryHierarchy = highestBoundaryHierarchy; + + // Get the list of boundary codes from pipe separated boundaryAncestralPath. + List boundaryCode = getBoundaryCodeFromAncestralPath(census.getBoundaryAncestralPath()); + + // Creates the mapping of boundary hierarchy with the corresponding boundary code. + for (String boundary : boundaryCode) { + jurisdictionMapping.put(boundaryHierarchy, boundary); + boundaryHierarchy = boundaryHierarchyMapping.get(boundaryHierarchy); + } + + census.setJurisdictionMapping(jurisdictionMapping); + } + + /** + * Enriches jurisdiction mapping for the list of census records for the given boundary ancestral path. + * + * @param censusList list of census data with boundary ancestral paths. + * @param boundaryTypeHierarchyDef boundary hierarchy for the given hierarchy type. + */ + public void enrichJurisdictionMapping(List censusList, BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef) { + Map boundaryHierarchyMapping = new HashMap<>(); + + // Enriches the boundaryHierarchyMapping and returns the highest boundary hierarchy for the given hierarchy type. + String highestBoundaryHierarchy = getBoundaryHierarchyMapping(boundaryTypeHierarchyDef, boundaryHierarchyMapping); + + for (Census census : censusList) { + + Map jurisdictionMapping = new LinkedHashMap<>(); + String boundaryHierarchy = highestBoundaryHierarchy; + + // Get the list of boundary codes from pipe separated boundaryAncestralPath. + List boundaryCode = getBoundaryCodeFromAncestralPath(census.getBoundaryAncestralPath()); + + // Creates the mapping of boundary hierarchy with the corresponding boundary code. + for (String boundary : boundaryCode) { + jurisdictionMapping.put(boundaryHierarchy, boundary); + boundaryHierarchy = boundaryHierarchyMapping.get(boundaryHierarchy); + } + + census.setJurisdictionMapping(jurisdictionMapping); + } + } + + /** + * Converts the boundaryAncestral path from a pipe separated string to an array of boundary codes. + * + * @param boundaryAncestralPath pipe separated boundaryAncestralPath. + * @return a list of boundary codes. + */ + private List getBoundaryCodeFromAncestralPath(List boundaryAncestralPath) { + if (CollectionUtils.isEmpty(boundaryAncestralPath)) { + return Collections.emptyList(); + } + return Arrays.asList(boundaryAncestralPath.get(0).split("\\|")); + } +} diff --git a/health-services/census-service/src/main/java/digit/service/enrichment/CensusTimeframeEnrichment.java b/health-services/census-service/src/main/java/digit/service/enrichment/CensusTimeframeEnrichment.java new file mode 100644 index 00000000000..fdd131957df --- /dev/null +++ b/health-services/census-service/src/main/java/digit/service/enrichment/CensusTimeframeEnrichment.java @@ -0,0 +1,47 @@ +package digit.service.enrichment; + +import digit.repository.CensusRepository; +import digit.web.models.Census; +import digit.web.models.CensusRequest; +import digit.web.models.CensusSearchCriteria; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; + +@Component +public class CensusTimeframeEnrichment { + + private CensusRepository repository; + + public CensusTimeframeEnrichment(CensusRepository repository) { + this.repository = repository; + } + + /** + * Enriches the effectiveTo of previous census records for the same boundary. + * + * @param request The census request. + */ + public void enrichPreviousTimeframe(CensusRequest request) { + Census census = request.getCensus(); + List censusList = repository.search(CensusSearchCriteria.builder().tenantId(census.getTenantId()).areaCodes(Collections.singletonList(census.getBoundaryCode())).effectiveTo(0L).build()); + + if (!CollectionUtils.isEmpty(censusList)) { + censusList.forEach(censusData -> { + censusData.setEffectiveTo(census.getAuditDetails().getCreatedTime()); + updatePreviousCensus(CensusRequest.builder().requestInfo(request.getRequestInfo()).census(censusData).build()); + }); + } + } + + /** + * Updates the timeframe of the previous census records. + * + * @param request the census to be updated. + */ + private void updatePreviousCensus(CensusRequest request) { + repository.update(request); + } +} diff --git a/health-services/census-service/src/main/java/digit/service/validator/CensusValidator.java b/health-services/census-service/src/main/java/digit/service/validator/CensusValidator.java new file mode 100644 index 00000000000..526e2445fb8 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/service/validator/CensusValidator.java @@ -0,0 +1,337 @@ +package digit.service.validator; + +import digit.config.Configuration; +import digit.repository.CensusRepository; +import digit.service.enrichment.CensusEnrichment; +import digit.util.BoundaryUtil; +import digit.util.PlanEmployeeAssignmnetUtil; +import digit.web.models.*; +import digit.web.models.boundary.BoundarySearchResponse; +import digit.web.models.boundary.BoundaryTypeHierarchyResponse; +import digit.web.models.boundary.HierarchyRelation; +import digit.web.models.plan.PlanEmployeeAssignmentResponse; +import digit.web.models.plan.PlanEmployeeAssignmentSearchCriteria; +import digit.web.models.plan.PlanEmployeeAssignmentSearchRequest; +import org.egov.common.contract.request.User; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.*; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.*; + +@Component +public class CensusValidator { + + private BoundaryUtil boundaryUtil; + + private PlanEmployeeAssignmnetUtil employeeAssignmnetUtil; + + private Configuration configs; + + private CensusRepository repository; + + private CensusEnrichment enrichment; + + public CensusValidator(BoundaryUtil boundaryUtil, PlanEmployeeAssignmnetUtil employeeAssignmnetUtil, Configuration configs, CensusRepository repository, CensusEnrichment enrichment) { + this.boundaryUtil = boundaryUtil; + this.employeeAssignmnetUtil = employeeAssignmnetUtil; + this.configs = configs; + this.repository = repository; + this.enrichment = enrichment; + } + + /** + * Validates boundary cade, partner assignment and jurisdiction for census create request + * + * @param request The create request for census + */ + public void validateCreate(CensusRequest request) { + Census census = request.getCensus(); + BoundarySearchResponse boundarySearchResponse = boundaryUtil.fetchBoundaryData(request.getRequestInfo(), census.getBoundaryCode(), census.getTenantId(), census.getHierarchyType(), Boolean.TRUE, Boolean.FALSE); + + // Validate duplicate records for census + validateDuplicateRecords(census); + + // Validate boundary code against boundary service + validateBoundaryCode(boundarySearchResponse, census); + + // Validate partner assignment and jurisdiction against plan service + validatePartnerForCensus(request); + + // Validate keys in additional field + validateAdditionalFields(request); + } + + private void validateDuplicateRecords(Census census) { + List censusResponseFromSearch = repository.search(CensusSearchCriteria.builder().source(census.getSource()).areaCodes(Collections.singletonList(census.getBoundaryCode())).build()); + + if(!CollectionUtils.isEmpty(censusResponseFromSearch)) { + throw new CustomException(CENSUS_ALREADY_EXISTS_CODE, CENSUS_ALREADY_EXISTS_MESSAGE); + } + } + + private void validateAdditionalFields(CensusRequest request) { + Set additionalFieldKeys = new HashSet<>(); + + request.getCensus().getAdditionalFields().forEach(additionalField -> { + if(additionalFieldKeys.contains(additionalField.getKey())) { + throw new CustomException(DUPLICATE_KEY_IN_ADDITIONAL_FIELD_CODE, DUPLICATE_KEY_IN_ADDITIONAL_FIELD_MESSGAE + additionalField.getKey()); + } + additionalFieldKeys.add(additionalField.getKey()); + }); + } + + /** + * Validates the boundary code provided in census request against boundary service. + * + * @param boundarySearchResponse response from the boundary service. + * @param census Census record whose boundary code is to be validated. + */ + private void validateBoundaryCode(BoundarySearchResponse boundarySearchResponse, Census census) { + HierarchyRelation tenantBoundary = boundarySearchResponse.getTenantBoundary().get(0); + + if (CollectionUtils.isEmpty(tenantBoundary.getBoundary())) { + throw new CustomException(NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE, NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE); + } + + // Enrich the boundary ancestral path and jurisdiction mapping for the provided boundary code + enrichment.enrichBoundaryAncestralPath(census, tenantBoundary); + } + + /** + * Validates partner assignment and jurisdiction against plan service + * Also validates the user information within the provided CensusRequest. + * + * @param request the census request + */ + private void validatePartnerForCensus(CensusRequest request) { + + Census census = request.getCensus(); + + // Validate the user information in the request + if (ObjectUtils.isEmpty(request.getRequestInfo().getUserInfo())) { + throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); + } + + if (census.getPartnerAssignmentValidationEnabled()) { + User userInfo = request.getRequestInfo().getUserInfo(); + List jurisdiction = Arrays.asList(request.getCensus().getBoundaryAncestralPath().get(0).split("\\|")); + + Set roles = new HashSet<>(configs.getAllowedCensusRoles()); + validateWorkflowAccess(userInfo, census, roles); + + PlanEmployeeAssignmentSearchCriteria searchCriteria = PlanEmployeeAssignmentSearchCriteria.builder() + .employeeId(Collections.singletonList(userInfo.getUuid())) + .planConfigurationId(request.getCensus().getSource()) + .tenantId(request.getCensus().getTenantId()) + .role(roles.stream().toList()) + .jurisdiction(jurisdiction) + .build(); + + PlanEmployeeAssignmentResponse employeeAssignmentResponse = employeeAssignmnetUtil.fetchPlanEmployeeAssignment(PlanEmployeeAssignmentSearchRequest.builder() + .requestInfo(request.getRequestInfo()) + .planEmployeeAssignmentSearchCriteria(searchCriteria) + .build()); + + if (CollectionUtils.isEmpty(employeeAssignmentResponse.getPlanEmployeeAssignment())) { + throw new CustomException(INVALID_PARTNER_CODE, INVALID_PARTNER_MESSAGE); + } + + //enrich jurisdiction of current assignee + request.getCensus().setAssigneeJurisdiction(employeeAssignmentResponse.getPlanEmployeeAssignment().get(0).getJurisdiction()); + } + } + + private void validateWorkflowAccess(User userInfo, Census census, Set roles) { + Boolean hasCensusRoles = userInfo.getRoles().stream() + .anyMatch(role -> configs.getAllowedCensusRoles().contains(role.getCode())); + + Boolean hasWfRestrictedRoles = userInfo.getRoles().stream() + .anyMatch(role -> configs.getWorkflowRestrictedRoles().contains(role.getCode())); + + if(hasWfRestrictedRoles) { + roles.addAll(configs.getWorkflowRestrictedRoles()); + + if(!hasCensusRoles && !ObjectUtils.isEmpty(census.getWorkflow())) + throw new CustomException(UNAUTHORIZED_WORKFLOW_ACCESS_CODE, UNAUTHORIZED_WORKFLOW_ACCESS_MESSAGE); + } + } + + /** + * Validates partner assignment and jurisdiction for census update request. + * + * @param request the update request for Census. + */ + public void validateUpdate(CensusRequest request) { + BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(request.getRequestInfo(), request.getCensus().getTenantId(), request.getCensus().getHierarchyType()); + + // Validate if Census record to be updated exists + validateCensusExistence(request); + + // Validate partner assignment and jurisdiction against plan service + validatePartnerForCensus(request); + + // Validate keys in additional field + validateAdditionalFields(request); + + // Enrich jurisdiction mapping in census + enrichment.enrichJurisdictionMapping(request.getCensus(), boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0)); + } + + /** + * Validates the existence of census record in the repository + * + * @param request The request containing the census to be validated + */ + private void validateCensusExistence(CensusRequest request) { + Census census = request.getCensus(); + CensusSearchCriteria searchCriteria = CensusSearchCriteria.builder() + .id(census.getId()) + .build(); + + List censusList = repository.search(searchCriteria); + + if (CollectionUtils.isEmpty(censusList)) { + throw new CustomException(INVALID_CENSUS_CODE, INVALID_CENSUS_MESSAGE); + } + + request.getCensus().setBoundaryAncestralPath(censusList.get(0).getBoundaryAncestralPath()); + } + + /** + * Validates census records for bulk update. + * Validates the census attributes, checks if census records to be validated exist. + * Also validates the partner assignment and jurisdiction for the given census records. + * + * @param request the census bulk update request. + */ + public void validateBulkUpdate(BulkCensusRequest request) { + BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(request.getRequestInfo(), request.getCensus().get(0).getTenantId(), request.getCensus().get(0).getHierarchyType()); + + // Validate attributes across each census in the bulk update request + validateCensusAttributes(request); + + // Validate if census in request body exists + validateCensusExistence(request); + + // Validate partner assignment and jurisdiction against plan service + validatePartnerForCensus(request); + + // Enrich jurisdiction mapping in census + enrichment.enrichJurisdictionMapping(request.getCensus(), boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0)); + } + + /** + * Validates partner assignment and jurisdiction against plan service + * Also validates the user information within the provided CensusRequest. + * + * @param request the census bulk update request + */ + private void validatePartnerForCensus(BulkCensusRequest request) { + + // Validate the user information in the request + if (ObjectUtils.isEmpty(request.getRequestInfo().getUserInfo())) { + throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); + } + + List jurisdiction = Arrays.asList(request.getCensus().get(0).getBoundaryAncestralPath().get(0).split("\\|")); + + PlanEmployeeAssignmentSearchCriteria searchCriteria = PlanEmployeeAssignmentSearchCriteria.builder() + .employeeId(Collections.singletonList(request.getRequestInfo().getUserInfo().getUuid())) + .planConfigurationId(request.getCensus().get(0).getSource()) + .tenantId(request.getCensus().get(0).getTenantId()) + .role(configs.getAllowedCensusRoles()) + .jurisdiction(jurisdiction) + .build(); + + PlanEmployeeAssignmentResponse employeeAssignmentResponse = employeeAssignmnetUtil.fetchPlanEmployeeAssignment(PlanEmployeeAssignmentSearchRequest.builder() + .requestInfo(request.getRequestInfo()) + .planEmployeeAssignmentSearchCriteria(searchCriteria) + .build()); + + if (CollectionUtils.isEmpty(employeeAssignmentResponse.getPlanEmployeeAssignment())) { + throw new CustomException(INVALID_PARTNER_CODE, INVALID_PARTNER_MESSAGE); + } + + //enrich jurisdiction of current assignee in all census records + request.getCensus().forEach(census -> census.setAssigneeJurisdiction(employeeAssignmentResponse.getPlanEmployeeAssignment().get(0).getJurisdiction())); + } + + /** + * Validates the existence of bulk census records in the repository + * + * @param request The request containing all the census records to be validated + */ + private void validateCensusExistence(BulkCensusRequest request) { + + // Get all census ids to validate existence + List censusListFromDatabase = repository.search(CensusSearchCriteria.builder() + .ids(request.getCensus().stream().map(Census::getId).collect(Collectors.toSet())) + .offset(0) + .limit(request.getCensus().size()) + .build()); + + // If census id provided is invalid, throw an exception + if (censusListFromDatabase.size() != request.getCensus().size()) { + throw new CustomException(INVALID_CENSUS_CODE, INVALID_CENSUS_MESSAGE); + } + + // Enrich boundary ancestral path for each census object being passed in the request + enrichBoundaryAncestralPath(request, censusListFromDatabase); + + } + + /** + * Enriches the census records with boundary ancestral path from repository. + * + * @param request bulk request with all census records. + * @param censusListFromDatabase existing census records from the repository. + */ + private void enrichBoundaryAncestralPath(BulkCensusRequest request, List censusListFromDatabase) { + Map censusIdVsBoundaryAncestralPathMap = censusListFromDatabase.stream() + .collect(Collectors.toMap(Census::getId, census -> census.getBoundaryAncestralPath().get(0))); + + request.getCensus().forEach(census -> + census.setBoundaryAncestralPath(Collections.singletonList(censusIdVsBoundaryAncestralPathMap + .get(census.getId()))) + ); + } + + /** + * Validates if census records provided in bulk update are unique. + * Checks if all the records have same source and tenant id. + * Also validates if records have same workflow status and action to be taken. + * + * @param request the census bulk update request + */ + private void validateCensusAttributes(BulkCensusRequest request) { + + if (request.getCensus().stream().map(Census::getId).collect(Collectors.toSet()).size() + != request.getCensus().size()) { + throw new CustomException(DUPLICATE_CENSUS_ID_IN_BULK_UPDATE_CODE, DUPLICATE_CENSUS_ID_IN_BULK_UPDATE_MESSAGE); + } + + if (!request.getCensus().stream().allMatch(census -> + census.getTenantId().equals(request.getCensus().get(0).getTenantId()) && + census.getSource().equals(request.getCensus().get(0).getSource()))) { + throw new CustomException(INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE_CODE, INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE_MESSAGE); + } + + request.getCensus().forEach(census -> { + if (ObjectUtils.isEmpty(census.getWorkflow())) { + throw new CustomException(WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE_CODE, WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE_MESSAGE); + } + }); + + if (!request.getCensus().stream().allMatch(census -> + census.getStatus().equals(request.getCensus().get(0).getStatus()) && + census.getWorkflow().getAction().equals(request.getCensus().get(0).getWorkflow().getAction()))) { + throw new CustomException(DIFFERENT_WORKFLOW_FOR_BULK_UPDATE_CODE, DIFFERENT_WORKFLOW_FOR_BULK_UPDATE_MESSAGE); + } + } +} + diff --git a/health-services/census-service/src/main/java/digit/service/workflow/WorkflowService.java b/health-services/census-service/src/main/java/digit/service/workflow/WorkflowService.java new file mode 100644 index 00000000000..e842c5dae29 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/service/workflow/WorkflowService.java @@ -0,0 +1,331 @@ +package digit.service.workflow; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.config.Configuration; +import digit.repository.ServiceRequestRepository; +import digit.util.PlanEmployeeAssignmnetUtil; +import digit.web.models.BulkCensusRequest; +import digit.web.models.Census; +import digit.web.models.CensusRequest; +import digit.web.models.plan.PlanEmployeeAssignmentResponse; +import digit.web.models.plan.PlanEmployeeAssignmentSearchCriteria; +import digit.web.models.plan.PlanEmployeeAssignmentSearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.Workflow; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.User; +import org.egov.common.contract.workflow.*; +import org.egov.common.utils.AuditDetailsEnrichmentUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.*; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.*; + +@Service +@Slf4j +public class WorkflowService { + + private ServiceRequestRepository serviceRequestRepository; + + private Configuration config; + + private ObjectMapper mapper; + + private PlanEmployeeAssignmnetUtil planEmployeeAssignmnetUtil; + + public WorkflowService(ServiceRequestRepository serviceRequestRepository, Configuration config, ObjectMapper mapper, PlanEmployeeAssignmnetUtil planEmployeeAssignmnetUtil) { + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.mapper = mapper; + this.planEmployeeAssignmnetUtil = planEmployeeAssignmnetUtil; + } + + /** + * Integrates with the workflow for the given census request. + * If the action is null, it does not proceed with integration. + * + * @param censusRequest The request containing the census object to integrate with the workflow. + */ + public void invokeWorkflowForStatusUpdate(CensusRequest censusRequest) { + if (ObjectUtils.isEmpty(censusRequest.getCensus().getWorkflow())) + return; + + ProcessInstanceRequest processInstanceRequest = createWorkflowRequest(censusRequest); + ProcessInstanceResponse processInstanceResponse = callWorkflowTransition(processInstanceRequest); + + // Setting the status back to the census object from workflow response + censusRequest.getCensus().setStatus(processInstanceResponse.getProcessInstances().get(0).getState().getState()); + + // Enrich audit details after auto assignment is complete + censusRequest.getCensus().setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails(censusRequest.getCensus().getAuditDetails(), censusRequest.getRequestInfo(), Boolean.FALSE)); + + } + + /** + * Integrates with the workflow for the given bulk census request. + * + * @param request The request containing the list of census objects to integrate with the workflow. + */ + public void invokeWorkflowForStatusUpdate(BulkCensusRequest request) { + + ProcessInstanceRequest processInstanceRequest = createWorkflowRequest(request); + ProcessInstanceResponse processInstanceResponse = callWorkflowTransition(processInstanceRequest); + + enrichCensusPostTransition(processInstanceResponse, request); + } + + /** + * Enriches the census records in bulk update with audit details and workflow status. + * + * @param processInstanceResponse process instance response containing the current workflow status + * @param request the bulk census request + */ + private void enrichCensusPostTransition(ProcessInstanceResponse processInstanceResponse, BulkCensusRequest request) { + // Update status and audit information post transition + request.getCensus().forEach(census -> { + // Update status of Census + census.setStatus(processInstanceResponse.getProcessInstances().get(0).getState().getState()); + + // Update audit information of census + census.setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails(census.getAuditDetails(), request.getRequestInfo(), Boolean.FALSE)); + }); + } + + /** + * Creates a workflow request from the given list of census records in bulk request. + * + * @param request The request containing the list of census to create a workflow request. + * @return The constructed process instance request for the workflow. + */ + private ProcessInstanceRequest createWorkflowRequest(BulkCensusRequest request) { + List processInstanceList = new ArrayList<>(); + + // Perform auto assignment + List assignee = getAssigneeForAutoAssignment(request.getCensus().get(0), request.getRequestInfo()); + + for (Census census : request.getCensus()) { + if (config.getWfSendBackActions().contains(census.getWorkflow().getAction())) { + assignee = Collections.singletonList(census.getAuditDetails().getLastModifiedBy()); + } + + // Set assignee + if (!ObjectUtils.isEmpty(assignee)) + census.getWorkflow().setAssignes(assignee); + + census.setAssignee(assignee); + + // Create process instance object from census + ProcessInstance processInstance = ProcessInstance.builder() + .businessId(census.getId()) + .tenantId(census.getTenantId()) + .businessService(CENSUS_BUSINESS_SERVICE) + .moduleName(MODULE_NAME_VALUE) + .action(census.getWorkflow().getAction()) + .comment(census.getWorkflow().getComments()) + .documents(census.getWorkflow().getDocuments()) + .build(); + + // Enrich user list for process instance + enrichAssignesInProcessInstance(processInstance, census.getWorkflow()); + + // Add entry for bulk transition + processInstanceList.add(processInstance); + } + + return ProcessInstanceRequest.builder() + .requestInfo(request.getRequestInfo()) + .processInstances(processInstanceList) + .build(); + } + + /** + * Calls the workflow transition service and retrieves the process instance response. + * + * @param processInstanceRequest The request containing process instance details for the workflow transition. + * @return The response containing details of the process instances after the transition. + * @throws CustomException if there is an error during the workflow integration. + */ + public ProcessInstanceResponse callWorkflowTransition(ProcessInstanceRequest processInstanceRequest) { + ProcessInstanceResponse processInstanceResponse; + try { + Object response = serviceRequestRepository.fetchResult(getWorkflowTransitionUri(), processInstanceRequest); + processInstanceResponse = mapper.convertValue(response, ProcessInstanceResponse.class); + } catch (Exception e) { + throw new CustomException(WORKFLOW_INTEGRATION_ERROR_CODE, WORKFLOW_INTEGRATION_ERROR_MESSAGE + e.getMessage()); + } + + return processInstanceResponse; + } + + /** + * Creates a workflow request from the given census request. + * + * @param censusRequest The request containing the census to create a workflow request. + * @return The constructed process instance request for the workflow. + */ + public ProcessInstanceRequest createWorkflowRequest(CensusRequest censusRequest) { + Census census = censusRequest.getCensus(); + + // Create process instance object from census + ProcessInstance processInstance = ProcessInstance.builder() + .businessId(census.getId()) + .tenantId(census.getTenantId()) + .businessService(CENSUS_BUSINESS_SERVICE) + .moduleName(MODULE_NAME_VALUE) + .action(census.getWorkflow().getAction()) + .comment(census.getWorkflow().getComments()) + .documents(census.getWorkflow().getDocuments()) + .build(); + + // Perform auto assignment + List assignee = getAssigneeForAutoAssignment(census, censusRequest.getRequestInfo()); + + if (config.getWfSendBackActions().contains(census.getWorkflow().getAction())) { + assignee = Collections.singletonList(census.getAuditDetails().getLastModifiedBy()); + } + + // Set Assignee + if (!ObjectUtils.isEmpty(assignee)) + census.getWorkflow().setAssignes(assignee); + + census.setAssignee(assignee); + + // Enrich user for process instance + enrichAssignesInProcessInstance(processInstance, census.getWorkflow()); + + log.info("Process Instance assignes - " + processInstance.getAssignes()); + return ProcessInstanceRequest.builder() + .requestInfo(censusRequest.getRequestInfo()) + .processInstances(Collections.singletonList(processInstance)) + .build(); + } + + /** + * Enriches the process instance with assignees from the given workflow. + * + * @param processInstance The process instance to enrich with assignees. + * @param workflow The workflow containing assignees to be added to the process instance. + */ + public void enrichAssignesInProcessInstance(ProcessInstance processInstance, Workflow workflow) { + List userList = CollectionUtils.isEmpty(workflow.getAssignes()) + ? new LinkedList<>() + : workflow.getAssignes().stream() + .map(assignee -> User.builder().uuid(assignee).build()) + .toList(); + + processInstance.setAssignes(userList); + } + + /** + * Constructs the URI for the workflow service transition API. + * + * @return The StringBuilder containing the constructed workflow transition URI. + */ + private StringBuilder getWorkflowTransitionUri() { + return new StringBuilder().append(config.getWfHost()).append(config.getWfTransitionPath()); + } + + /** + * Returns a list of assignee based on the workflow action and jurisdiction hierarchy. + * Retrieves jurisdiction boundaries from the census request and searches for matching employee assignments. + * + * For INITIATE actions, assigns the employee from the lowest boundary. + * For INTERMEDIATE actions (non-ROOT_APPROVER), assigns an employee from a higher-level boundary. + * For SEND_BACK actions, assigns the last modified user. + * + * @param census the census object containing workflow and jurisdiction details + * @param requestInfo the requestInfo + */ + private List getAssigneeForAutoAssignment(Census census, RequestInfo requestInfo) { + String[] allHierarchiesBoundaryCodes = census.getBoundaryAncestralPath().get(0).split(PIPE_REGEX); + String[] hierarchiesBoundaryCodes = Arrays.copyOf(allHierarchiesBoundaryCodes, allHierarchiesBoundaryCodes.length - 1); + + PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = + PlanEmployeeAssignmentSearchCriteria.builder() + .tenantId(census.getTenantId()) + .jurisdiction(Arrays.stream(hierarchiesBoundaryCodes).toList()) + .planConfigurationId(census.getSource()) + .role(config.getAllowedCensusRoles()) + .build(); + + //search for plan-employee assignments for the ancestral hierarchy codes. + PlanEmployeeAssignmentResponse planEmployeeAssignmentResponse = planEmployeeAssignmnetUtil.fetchPlanEmployeeAssignment(PlanEmployeeAssignmentSearchRequest.builder() + .planEmployeeAssignmentSearchCriteria(planEmployeeAssignmentSearchCriteria) + .requestInfo(requestInfo).build()); + + // Create a map of jurisdiction to list of employeeIds + Map> jurisdictionToEmployeeMap = planEmployeeAssignmentResponse.getPlanEmployeeAssignment().stream() + .filter(assignment -> !CollectionUtils.isEmpty(assignment.getJurisdiction())) + .flatMap(assignment -> { + String employeeId = assignment.getEmployeeId(); + return assignment.getJurisdiction().stream() + .filter(jurisdiction -> Arrays.asList(hierarchiesBoundaryCodes).contains(jurisdiction)) + .map(jurisdiction -> new AbstractMap.SimpleEntry<>(jurisdiction, employeeId)); + }) + .collect(Collectors.groupingBy( + Map.Entry::getKey, // jurisdiction as the key + LinkedHashMap::new, // Preserve insertion order + Collectors.mapping( + Map.Entry::getValue, // employee IDs as values + Collectors.toList() // Collect employee IDs into a List + ) + )); + + List assignee = null; //assignee will remain null in case terminate actions are being taken + + String action = census.getWorkflow().getAction(); + if (config.getWfInitiateActions().contains(action)) { + for (int i = hierarchiesBoundaryCodes.length - 1; i >= 0; i--) { + assignee = jurisdictionToEmployeeMap.get(hierarchiesBoundaryCodes[i]); + if (assignee != null) + break; // Stop iterating once an assignee is found + } + } else if (config.getWfIntermediateActions().contains(action)) { + assignee = assignToHigherBoundaryLevel(hierarchiesBoundaryCodes, census, jurisdictionToEmployeeMap); + } + + return assignee; + } + + /** + * Assigns a list of employees from a higher-level jurisdiction in the hierarchy. + * Iterates through boundary codes, checking if they match the assignee's jurisdiction. + * If a higher-level boundary has an assigned employee, returns that employee's ID. + * + * @param heirarchysBoundaryCodes boundary codes representing the hierarchy + * @param census the census object with jurisdiction details + * @param jurisdictionToEmployeeMap map of jurisdiction codes to employee IDs + * @return the list of employee IDs from the higher boundary, or null if + */ + public List assignToHigherBoundaryLevel(String[] heirarchysBoundaryCodes, Census census, Map> jurisdictionToEmployeeMap) { + for (int i = heirarchysBoundaryCodes.length - 1; i >= 0; i--) { + String boundaryCode = heirarchysBoundaryCodes[i]; + + // Check if this boundary code is present in assigneeJurisdiction + if (census.getAssigneeJurisdiction().contains(boundaryCode)) { + + for (int j = i - 1; j >= 0; j--) { + // Check the next higher level in the hierarchy (one index above the match) + String higherBoundaryCode = heirarchysBoundaryCodes[j]; + + // Fetch the employeeId from the map for the higher boundary code + List employeeId = jurisdictionToEmployeeMap.get(higherBoundaryCode); + + // If an employee is found, set them as the assignee and break the loop + if (employeeId != null) { + return employeeId; + } + } + } + } + return null; + } + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/util/BoundaryUtil.java b/health-services/census-service/src/main/java/digit/util/BoundaryUtil.java new file mode 100644 index 00000000000..8e977cf3ccb --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/BoundaryUtil.java @@ -0,0 +1,111 @@ +package digit.util; + +import digit.config.Configuration; +import digit.web.models.RequestInfoWrapper; +import digit.web.models.boundary.BoundarySearchResponse; +import digit.web.models.boundary.BoundaryTypeHierarchyResponse; +import digit.web.models.boundary.BoundaryTypeHierarchySearchCriteria; +import digit.web.models.boundary.BoundaryTypeHierarchySearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_BOUNDARY_DETAILS; +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS; + +@Slf4j +@Component +public class BoundaryUtil { + + private RestTemplate restTemplate; + + private Configuration configs; + + public BoundaryUtil(RestTemplate restTemplate, Configuration configs) { + this.restTemplate = restTemplate; + this.configs = configs; + } + + /** + * This method fetches boundary relationships from Boundary service for the provided boundaryCode and hierarchyType. + * + * @param requestInfo request info from the request. + * @param boundaryCode boundary code from the request. + * @param tenantId tenant id from the request. + * @param hierarchyType hierarchy type from the request. + * @param includeParents is true if you want to include parent boundary. + * @param includeChildren is true if you want to include child boundary. + * @return returns the response from boundary service + */ + public BoundarySearchResponse fetchBoundaryData(RequestInfo requestInfo, String boundaryCode, String tenantId, String hierarchyType, Boolean includeParents, Boolean includeChildren) { + + // Create Boundary Relationship search uri + Map uriParameters = new HashMap<>(); + StringBuilder uri = getBoundaryRelationshipSearchUri(uriParameters, boundaryCode, tenantId, hierarchyType, includeParents, includeChildren); + + // Create request body + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); + BoundarySearchResponse boundarySearchResponse = new BoundarySearchResponse(); + + try { + boundarySearchResponse = restTemplate.postForObject(uri.toString(), requestInfoWrapper, BoundarySearchResponse.class, uriParameters); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BOUNDARY_DETAILS, e); + } + + return boundarySearchResponse; + } + + /** + * This method creates Boundary service uri with query parameters + * + * @param uriParameters map that stores values corresponding to the placeholder in uri + * @param boundaryCode boundary code from the request. + * @param tenantId tenant id from the request. + * @param hierarchyType hierarchy type from the request. + * @param includeParents is true if you want to include parent boundary. + * @param includeChildren is true if you want to include child boundary. + * @return a complete boundary service uri + */ + private StringBuilder getBoundaryRelationshipSearchUri(Map uriParameters, String boundaryCode, String tenantId, String hierarchyType, Boolean includeParents, Boolean includeChildren) { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getBoundaryServiceHost()).append(configs.getBoundaryRelationshipSearchEndpoint()).append("?codes={boundaryCode}&includeParents={includeParents}&includeChildren={includeChildren}&tenantId={tenantId}&hierarchyType={hierarchyType}"); + + uriParameters.put("boundaryCode", boundaryCode); + uriParameters.put("tenantId", tenantId); + uriParameters.put("includeParents", includeParents.toString()); + uriParameters.put("includeChildren", includeChildren.toString()); + uriParameters.put("hierarchyType", hierarchyType); + + return uri; + } + + public BoundaryTypeHierarchyResponse fetchBoundaryHierarchy(RequestInfo requestInfo, String tenantId, String hierarchyType) { + + // Create Boundary hierarchy search uri + String uri = getBoundaryHierarchySearchUri(); + + // Create request body + BoundaryTypeHierarchySearchCriteria searchCriteria = BoundaryTypeHierarchySearchCriteria.builder().tenantId(tenantId).hierarchyType(hierarchyType).build(); + BoundaryTypeHierarchySearchRequest searchRequest = BoundaryTypeHierarchySearchRequest.builder().requestInfo(requestInfo).boundaryTypeHierarchySearchCriteria(searchCriteria).build(); + BoundaryTypeHierarchyResponse searchResponse = new BoundaryTypeHierarchyResponse(); + + try { + searchResponse = restTemplate.postForObject(uri, searchRequest, BoundaryTypeHierarchyResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS, e); + } + + return searchResponse; + } + + private String getBoundaryHierarchySearchUri() { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getBoundaryServiceHost()).append(configs.getBoundaryHierarchySearchEndpoint()); + return uri.toString(); + } +} diff --git a/health-services/census-service/src/main/java/digit/util/BusinessServiceUtil.java b/health-services/census-service/src/main/java/digit/util/BusinessServiceUtil.java new file mode 100644 index 00000000000..ce127d4c637 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/BusinessServiceUtil.java @@ -0,0 +1,81 @@ +package digit.util; + +import digit.config.Configuration; +import digit.models.coremodels.RequestInfoWrapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.workflow.BusinessService; +import org.egov.common.contract.workflow.BusinessServiceResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class BusinessServiceUtil { + + private RestTemplate restTemplate; + + private Configuration config; + + public BusinessServiceUtil(RestTemplate restTemplate, Configuration configs) { + this.restTemplate = restTemplate; + this.config = configs; + } + + /** + * This method fetches business service details for the given tenant id and business service. + * + * @param requestInfo the request info from request. + * @param businessService businessService whose details are to be searched. + * @param tenantId tenantId from request. + * @return returns the business service response for the given tenant id and business service. + */ + public BusinessService fetchBusinessService(RequestInfo requestInfo, String businessService, String tenantId) { + + // Get business service uri + Map uriParameters = new HashMap<>(); + String uri = getBusinessServiceUri(businessService, tenantId, uriParameters); + + // Create request body + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); + BusinessServiceResponse businessServiceResponse = new BusinessServiceResponse(); + + try { + businessServiceResponse = restTemplate.postForObject(uri, requestInfoWrapper, BusinessServiceResponse.class, uriParameters); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BUSINESS_SERVICE_DETAILS, e); + } + + if (CollectionUtils.isEmpty(businessServiceResponse.getBusinessServices())) { + throw new CustomException(NO_BUSINESS_SERVICE_DATA_FOUND_CODE, NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE); + } + + return businessServiceResponse.getBusinessServices().get(0); + } + + /** + * This method creates business service uri with query parameters + * + * @param businessService businessService whose details are to be searched. + * @param tenantId tenant id from the request. + * @param uriParameters map that stores values corresponding to the placeholder in uri + * @return + */ + private String getBusinessServiceUri(String businessService, String tenantId, Map uriParameters) { + + StringBuilder uri = new StringBuilder(); + uri.append(config.getWfHost()).append(config.getBusinessServiceSearchEndpoint()).append("?tenantId={tenantId}&businessServices={businessService}"); + + uriParameters.put("tenantId", tenantId); + uriParameters.put("businessService", businessService); + + return uri.toString(); + } +} diff --git a/health-services/census-service/src/main/java/digit/util/CommonUtil.java b/health-services/census-service/src/main/java/digit/util/CommonUtil.java new file mode 100644 index 00000000000..bf473f57cac --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/CommonUtil.java @@ -0,0 +1,151 @@ +package digit.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import digit.web.models.CensusSearchCriteria; +import digit.web.models.CensusSearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.workflow.BusinessService; +import org.egov.common.contract.workflow.State; +import org.egov.tracer.model.CustomException; +import org.postgresql.util.PGobject; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.sql.SQLException; +import java.util.*; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class CommonUtil { + + private ObjectMapper objectMapper; + + private BusinessServiceUtil businessServiceUtil; + + public CommonUtil(ObjectMapper objectMapper, BusinessServiceUtil businessServiceUtil) { + this.objectMapper = objectMapper; + this.businessServiceUtil = businessServiceUtil; + } + + /** + * Adds or updates the value of provided field in the additional details object. + * @param additionalDetails + * @param fieldToUpdate + * @param updatedValue + * @return + */ + public Map updateFieldInAdditionalDetails(Object additionalDetails, String fieldToUpdate, String updatedValue) { + try { + + // Get or create the additionalDetails as an ObjectNode + ObjectNode objectNode = additionalDetails instanceof NullNode + ? objectMapper.createObjectNode() + : objectMapper.convertValue(additionalDetails, ObjectNode.class); + + // Update or Add the field in additional details object + objectNode.put(fieldToUpdate, updatedValue); + + // Convert updated ObjectNode back to a Map and set it in 'additionalDetails' + Map updatedDetails = objectMapper.convertValue(objectNode, Map.class); + return updatedDetails; + + } catch (Exception e) { + throw new CustomException(ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE, ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE); + } + } + + public Map updateFieldInAdditionalDetails(Object additionalDetails, Map fieldsToBeUpdated) { + try { + + // Get or create the additionalDetails as an ObjectNode + ObjectNode objectNode = (additionalDetails == null || additionalDetails instanceof NullNode) + ? objectMapper.createObjectNode() + : objectMapper.convertValue(additionalDetails, ObjectNode.class); + + // Update or add the field in additional details object + fieldsToBeUpdated.forEach((key, value) -> objectNode.set(key, objectMapper.valueToTree(value))); + + // Convert updated ObjectNode back to a Map + return objectMapper.convertValue(objectNode, Map.class); + + } catch (Exception e) { + throw new CustomException(ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE, ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE + e); + } + } + + /** + * Removes the field to be removed from the additional details object. + * @param additionalDetails + * @param fieldToBeRemoved + * @return + */ + public Map removeFieldFromAdditionalDetails(Object additionalDetails, String fieldToBeRemoved) { + Map additionalDetailsMap = objectMapper.convertValue(additionalDetails, Map.class); + additionalDetailsMap.remove(fieldToBeRemoved); + + return additionalDetailsMap; + } + + /** + * Creates the census search request for the provided details. + * @param tenantId + * @param planConfigId + * @param serviceBoundary + * @return + */ + public CensusSearchRequest getCensusSearchRequest(String tenantId, String planConfigId, String serviceBoundary, List initiallySetServiceBoundaries, RequestInfo requestInfo) { + Set areaCodesForSearch = new HashSet<>(); + + areaCodesForSearch.addAll(Arrays.asList(serviceBoundary.split(","))); + areaCodesForSearch.addAll(initiallySetServiceBoundaries); + + CensusSearchCriteria searchCriteria = CensusSearchCriteria.builder() + .tenantId(tenantId) + .source(planConfigId) + .areaCodes(areaCodesForSearch.stream().toList()) + .offset(0) + .limit(areaCodesForSearch.size()) + .build(); + + return CensusSearchRequest.builder().requestInfo(requestInfo).censusSearchCriteria(searchCriteria).build(); + } + + /** + * Creates a list of all the workflow states for the provided business service. + * @param requestInfo + * @param businessService + * @param tenantId + * @return + */ + public List getStatusFromBusinessService(RequestInfo requestInfo, String businessService, String tenantId) { + BusinessService businessServices = businessServiceUtil.fetchBusinessService(requestInfo, businessService, tenantId); + + return businessServices.getStates().stream() + .map(State::getState) + .filter(state -> !ObjectUtils.isEmpty(state)) + .toList(); + } + + public PGobject convertToPgObject(Object additionalDetails) { + PGobject pGobject = new PGobject(); + + try { + String json = objectMapper.writeValueAsString(additionalDetails); + + pGobject.setType("jsonb"); + pGobject.setValue(json); + } catch (JsonProcessingException e) { + log.error("Error while processing JSON object to string", e); + } catch (SQLException e) { + log.error("Error while setting JSONB object", e); + } + + return pGobject; + } +} diff --git a/health-services/census-service/src/main/java/digit/util/PlanEmployeeAssignmnetUtil.java b/health-services/census-service/src/main/java/digit/util/PlanEmployeeAssignmnetUtil.java new file mode 100644 index 00000000000..0cb18bdb6db --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/PlanEmployeeAssignmnetUtil.java @@ -0,0 +1,59 @@ +package digit.util; + +import digit.config.Configuration; +import digit.web.models.plan.PlanEmployeeAssignmentResponse; +import digit.web.models.plan.PlanEmployeeAssignmentSearchCriteria; +import digit.web.models.plan.PlanEmployeeAssignmentSearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_EMPLOYEE_ASSIGNMENT_DETAILS; + +@Slf4j +@Component +public class PlanEmployeeAssignmnetUtil { + + private RestTemplate restTemplate; + + private Configuration config; + + public PlanEmployeeAssignmnetUtil(RestTemplate restTemplate, Configuration configs) { + this.restTemplate = restTemplate; + this.config = configs; + } + + /** + * This method fetches plan employee assignment from plan service for provided employeeID. + * @param planEmployeeAssignmentSearchRequest request containint the planEmployeeAssignment search criteria + * @return returns planEmployeeAssignment for provided search criteria. + */ + public PlanEmployeeAssignmentResponse fetchPlanEmployeeAssignment(PlanEmployeeAssignmentSearchRequest planEmployeeAssignmentSearchRequest) { + + // Get plan employee assignment uri + StringBuilder uri = getPlanEmployeeAssignmentUri(); + + PlanEmployeeAssignmentResponse response = new PlanEmployeeAssignmentResponse(); + + try { + response = restTemplate.postForObject(uri.toString(), planEmployeeAssignmentSearchRequest, PlanEmployeeAssignmentResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_EMPLOYEE_ASSIGNMENT_DETAILS, e); + } + + return response; + } + + /** + * This method creates the uri for plan employee assignment search + * + * @return uri for plan employee assignment search + */ + private StringBuilder getPlanEmployeeAssignmentUri() { + StringBuilder uri = new StringBuilder(); + return uri.append(config.getPlanServiceHost()).append(config.getPlanEmployeeAssignmentSearchEndpoint()); + } +} diff --git a/health-services/census-service/src/main/java/digit/util/QueryUtil.java b/health-services/census-service/src/main/java/digit/util/QueryUtil.java new file mode 100644 index 00000000000..3d9354df7a3 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/QueryUtil.java @@ -0,0 +1,139 @@ +package digit.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.config.Configuration; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.CustomException; +import org.postgresql.util.PGobject; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.stream.IntStream; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class QueryUtil { + + private Configuration config; + + private ObjectMapper objectMapper; + + private QueryUtil(Configuration config, ObjectMapper objectMapper) { + this.config = config; + this.objectMapper = objectMapper; + } + + /** + * This method adds "WHERE" clause and "AND" condition depending on preparedStatementList i.e., + * if preparedStatementList is empty, it will understand that it is the first clause being added so it + * will add "WHERE" to the query and otherwise it will + * + * @param query query to which Clause is to be added. + * @param preparedStmtList prepared statement list to check which clause to add. + */ + public void addClauseIfRequired(StringBuilder query, List preparedStmtList) { + if (preparedStmtList.isEmpty()) { + query.append(" WHERE "); + } else { + query.append(" AND "); + } + } + + /** + * This method returns a string with placeholders equal to the number of values that need to be put inside + * "IN" clause + * + * @param size number of placeholders to be added. + * @return a string with provided number of placeholders. + */ + public String createQuery(Integer size) { + StringBuilder builder = new StringBuilder(); + + IntStream.range(0, size).forEach(i -> { + builder.append(" ?"); + if (i != size - 1) + builder.append(","); + }); + + return builder.toString(); + } + + /** + * This method adds a set of String values into preparedStatementList. + * + * @param preparedStmtList prepared statement list to add Ids. + * @param ids set of Ids to be added. + */ + public void addToPreparedStatement(List preparedStmtList, Set ids) { + ids.forEach(id -> { + preparedStmtList.add(id); + }); + } + + public void addToPreparedStatement(List preparedStmtList, List ids) { + ids.forEach(id -> { + preparedStmtList.add(id); + }); + } + + /** + * This method appends order by clause to the query. + * + * @param query the query to which orderBy clause is to be added. + * @param orderByClause the orderBy clause to be added. + * @return a query with orderBy clause. + */ + public String addOrderByClause(String query, String orderByClause) { + return query + orderByClause; + } + + /** + * This method appends pagination i.e. limit and offset to the query. + * + * @param query the query to which pagination is to be added. + * @param preparedStmtList prepared statement list to add limit and offset. + * @return a query with pagination + */ + public String getPaginatedQuery(String query, List preparedStmtList) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(config.getDefaultOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(config.getDefaultLimit()); + + return paginatedQuery.toString(); + } + + /** + * This method is used to extract and parse JSON data into a JsonNode object. + * + * @param pgObject postgreSQL specific object. + * @return returns a JsonNode. + */ + public JsonNode parseJson(PGobject pgObject) { + + try { + if (!ObjectUtils.isEmpty(pgObject)) { + return objectMapper.readTree(pgObject.getValue()); + } + } catch (IOException e) { + log.error("Error parsing PGobject value: " + pgObject, e); + throw new CustomException(PARSING_ERROR_CODE, PARSING_ERROR_MESSAGE); + } + + // Return empty JsonNode if pgObject is empty + return objectMapper.createObjectNode(); + } + + +} diff --git a/health-services/census-service/src/main/java/digit/util/ResponseInfoFactory.java b/health-services/census-service/src/main/java/digit/util/ResponseInfoFactory.java new file mode 100644 index 00000000000..a10e7f50841 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/ResponseInfoFactory.java @@ -0,0 +1,27 @@ +package digit.util; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.stereotype.Component; + +import static digit.config.ServiceConstants.*; + +@Component +public class ResponseInfoFactory { + + public ResponseInfo createResponseInfoFromRequestInfo(final RequestInfo requestInfo, final Boolean success) { + + final String apiId = requestInfo != null ? requestInfo.getApiId() : ""; + final String ver = requestInfo != null ? requestInfo.getVer() : ""; + Long ts = null; + if (requestInfo != null) + ts = requestInfo.getTs(); + + final String msgId = requestInfo != null ? requestInfo.getMsgId() : ""; + final String responseStatus = success ? SUCCESSFUL : FAILED; + + return ResponseInfo.builder().apiId(apiId).ver(ver).ts(ts).resMsgId(RES_MSG_ID).msgId(msgId).resMsgId(RES_MSG_ID) + .status(responseStatus).build(); + } + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/web/controllers/CensusController.java b/health-services/census-service/src/main/java/digit/web/controllers/CensusController.java new file mode 100644 index 00000000000..8feabf4b455 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/controllers/CensusController.java @@ -0,0 +1,76 @@ +package digit.web.controllers; + +import digit.service.CensusService; +import digit.web.models.BulkCensusRequest; +import digit.web.models.CensusRequest; +import digit.web.models.CensusResponse; +import digit.web.models.CensusSearchRequest; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + + +@Controller +public class CensusController { + + private CensusService censusService; + + public CensusController(CensusService censusService) { + this.censusService = censusService; + } + + /** + * Request handler for serving census create requests + * + * @param body + * @return + */ + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity create(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody CensusRequest body) { + CensusResponse response = censusService.create(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + /** + * Request handler for serving census search requests + * + * @param body + * @return + */ + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity search(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody CensusSearchRequest body) { + CensusResponse response = censusService.search(body); + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * Request handler for serving census update requests + * + * @param body + * @return + */ + @RequestMapping(value = "/_update", method = RequestMethod.POST) + public ResponseEntity update(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody CensusRequest body) { + CensusResponse response = censusService.update(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + /** + * Request handler for serving bulk census update requests + * + * @param body + * @return + */ + @RequestMapping(value = "/bulk/_update", method = RequestMethod.POST) + public ResponseEntity bulkUpdate(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody BulkCensusRequest body) { + CensusResponse response = censusService.bulkUpdate(body); + return ResponseEntity.status(HttpStatus.CREATED).body(response); + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java b/health-services/census-service/src/main/java/digit/web/models/AdditionalField.java similarity index 52% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java rename to health-services/census-service/src/main/java/digit/web/models/AdditionalField.java index b8ed98d54e8..10351283cdb 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java +++ b/health-services/census-service/src/main/java/digit/web/models/AdditionalField.java @@ -1,8 +1,9 @@ -package org.egov.processor.web.models; +package digit.web.models; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; -import jakarta.validation.constraints.*; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -12,34 +13,36 @@ import java.math.BigDecimal; /** - * Assumption + * AdditionalField */ @Validated @Data @AllArgsConstructor @NoArgsConstructor @Builder -public class Assumption { +public class AdditionalField { + @JsonProperty("id") @Valid @Size(min = 2, max = 64) private String id = null; @JsonProperty("key") + @Valid @NotNull - @Size(min = 1, max = 256) private String key = null; @JsonProperty("value") - @NotNull @Valid - @DecimalMin(value = "0.01", inclusive = true, message = "Assumption value must be greater than 0") - @DecimalMax(value = "999.99", inclusive = true, message = "Assumption value must be less than 1000") - @Digits(integer = 3, fraction = 2, message = "Assumption value must have up to 3 digits and up to 2 decimal points") + @NotNull private BigDecimal value = null; - @JsonProperty("active") - @NotNull - private Boolean active = true; + @JsonProperty("showOnUi") + private Boolean showOnUi = Boolean.TRUE; + + @JsonProperty("editable") + private Boolean editable = Boolean.TRUE; + @JsonProperty("order") + private Integer order = null; } diff --git a/health-services/census-service/src/main/java/digit/web/models/BulkCensusRequest.java b/health-services/census-service/src/main/java/digit/web/models/BulkCensusRequest.java new file mode 100644 index 00000000000..e88178822bb --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/BulkCensusRequest.java @@ -0,0 +1,33 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * BulkCensusRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BulkCensusRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Census") + @Valid + private List census = null; + + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/Census.java b/health-services/census-service/src/main/java/digit/web/models/Census.java new file mode 100644 index 00000000000..55ed850ff18 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/Census.java @@ -0,0 +1,142 @@ +package digit.web.models; + + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +import java.util.List; +import java.util.Map; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; + + +/** + * Census + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Census { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @NotNull + private String hierarchyType = null; + + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode = null; + + @JsonProperty("assignee") + private List assignee = null; + + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("type") + @NotNull + private TypeEnum type = null; + + @JsonProperty("totalPopulation") + @NotNull + private Long totalPopulation = null; + + @JsonProperty("populationByDemographics") + @Valid + private List populationByDemographics = null; + + @JsonProperty("additionalFields") + @Valid + private List additionalFields = null; + + @JsonProperty("effectiveFrom") + private Long effectiveFrom = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("source") + @NotNull + private String source = null; + + @JsonIgnore + private List boundaryAncestralPath = null; + + @JsonIgnore + @Builder.Default + private Boolean partnerAssignmentValidationEnabled = Boolean.TRUE; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; + + /** + * Gets or Sets type + */ + public enum TypeEnum { + PEOPLE("people"), + ANIMALS("animals"), + PLANTS("plants"), + OTHER("other"); + + private String value; + + TypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static TypeEnum fromValue(String text) { + for (TypeEnum b : TypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusDTO.java b/health-services/census-service/src/main/java/digit/web/models/CensusDTO.java new file mode 100644 index 00000000000..02d3c7d1b2b --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusDTO.java @@ -0,0 +1,104 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Map; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; + + +/** + * CensusDTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusDTO { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @NotNull + private String hierarchyType = null; + + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("type") + @NotNull + private String type = null; + + @JsonProperty("totalPopulation") + @NotNull + private Long totalPopulation = null; + + @JsonProperty("populationByDemographics") + @Valid + private List populationByDemographics = null; + + @JsonProperty("additionalFields") + @Valid + private List additionalFields = null; + + @JsonProperty("effectiveFrom") + private Long effectiveFrom = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("source") + @NotNull + private String source = null; + + @JsonProperty("boundaryAncestralPath") + private String boundaryAncestralPath = null; + + @JsonIgnore + private boolean partnerAssignmentValidationEnabled; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusRequest.java b/health-services/census-service/src/main/java/digit/web/models/CensusRequest.java new file mode 100644 index 00000000000..d8755bbbda9 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusRequest.java @@ -0,0 +1,31 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Census") + @Valid + private Census census = null; + + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusRequestDTO.java b/health-services/census-service/src/main/java/digit/web/models/CensusRequestDTO.java new file mode 100644 index 00000000000..7b1ced9a7db --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusRequestDTO.java @@ -0,0 +1,31 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusRequestDTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusRequestDTO { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Census") + @Valid + private CensusDTO censusDTO = null; + + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusResponse.java b/health-services/census-service/src/main/java/digit/web/models/CensusResponse.java new file mode 100644 index 00000000000..4aace9435f2 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusResponse.java @@ -0,0 +1,42 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Map; + +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Census") + @Valid + private List census = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + @JsonProperty("StatusCount") + @Valid + private Map statusCount = null; + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusSearchCriteria.java b/health-services/census-service/src/main/java/digit/web/models/CensusSearchCriteria.java new file mode 100644 index 00000000000..363da1907ae --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusSearchCriteria.java @@ -0,0 +1,72 @@ +package digit.web.models; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.springframework.validation.annotation.Validated; +import jakarta.validation.constraints.*; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchCriteria { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("ids") + private Set ids = null; + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + private String tenantId = null; + + @JsonProperty("areaCodes") + private List areaCodes = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("source") + private String source = null; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("jurisdiction") + private List jurisdiction = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("limit") + private Integer limit = null; + + @JsonProperty("offset") + private Integer offset = null; + + public CensusSearchCriteria addAreaCodesItem(String areaCodesItem) { + if (this.areaCodes == null) { + this.areaCodes = new ArrayList<>(); + } + this.areaCodes.add(areaCodesItem); + return this; + } + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusSearchRequest.java b/health-services/census-service/src/main/java/digit/web/models/CensusSearchRequest.java new file mode 100644 index 00000000000..ac595972fe7 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusSearchRequest.java @@ -0,0 +1,33 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("CensusSearchCriteria") + @Valid + @NotNull + private CensusSearchCriteria censusSearchCriteria = null; + + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/PopulationByDemographic.java b/health-services/census-service/src/main/java/digit/web/models/PopulationByDemographic.java new file mode 100644 index 00000000000..8b984e06d89 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/PopulationByDemographic.java @@ -0,0 +1,69 @@ +package digit.web.models; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PopulationByDemographic + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PopulationByDemographic { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("demographicVariable") + private DemographicVariableEnum demographicVariable = null; + + @JsonProperty("populationDistribution") + private Object populationDistribution = null; + + /** + * Gets or Sets demographicVariable + */ + public enum DemographicVariableEnum { + AGE("age"), + + GENDER("gender"), + + ETHNICITY("ethnicity"); + + private String value; + + DemographicVariableEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DemographicVariableEnum fromValue(String text) { + for (DemographicVariableEnum b : DemographicVariableEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/RequestInfoWrapper.java b/health-services/census-service/src/main/java/digit/web/models/RequestInfoWrapper.java new file mode 100644 index 00000000000..b36665e3e25 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/RequestInfoWrapper.java @@ -0,0 +1,18 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.egov.common.contract.request.RequestInfo; + + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class RequestInfoWrapper { + + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java new file mode 100644 index 00000000000..7f92e1f53c8 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java @@ -0,0 +1,42 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * BoundarySearchResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("TenantBoundary") + @Valid + private List tenantBoundary = null; + + + public BoundarySearchResponse addTenantBoundaryItem(HierarchyRelation tenantBoundaryItem) { + if (this.tenantBoundary == null) { + this.tenantBoundary = new ArrayList<>(); + } + this.tenantBoundary.add(tenantBoundaryItem); + return this; + } + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java new file mode 100644 index 00000000000..45ab5a19141 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java @@ -0,0 +1,30 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryTypeHierarchy + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchy { + + @JsonProperty("boundaryType") + private String boundaryType = null; + + @JsonProperty("parentBoundaryType") + private String parentBoundaryType = null; + + @JsonProperty("active") + private Boolean active = null; + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java new file mode 100644 index 00000000000..6faf8ac0b49 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java @@ -0,0 +1,45 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * BoundaryTypeHierarchyDefinition + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchyDefinition { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("hierarchyType") + private String hierarchyType = null; + + @JsonProperty("boundaryHierarchy") + @Valid + private List boundaryHierarchy = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("boundaryHierarchyJsonNode") + private JsonNode boundaryHierarchyJsonNode = null; + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java new file mode 100644 index 00000000000..6372620c43c --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java @@ -0,0 +1,36 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * BoundaryTypeHierarchyResponse + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchyResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("totalCount") + private Integer totalCount = null; + + @JsonProperty("BoundaryHierarchy") + @Valid + private List boundaryHierarchy = null; + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java new file mode 100644 index 00000000000..7ad5be0790f --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java @@ -0,0 +1,38 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.constraints.*; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * BoundaryTypeHierarchySearchCriteria + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchySearchCriteria { + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @Size(min = 1, max = 100) + private String hierarchyType = null; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} + diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java new file mode 100644 index 00000000000..b85ffffd857 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java @@ -0,0 +1,33 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import jakarta.validation.Valid; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * BoundaryTypeHierarchySearchRequest + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchySearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("BoundaryTypeHierarchySearchCriteria") + @Valid + private BoundaryTypeHierarchySearchCriteria boundaryTypeHierarchySearchCriteria = null; + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java b/health-services/census-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java new file mode 100644 index 00000000000..c42af3737ce --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java @@ -0,0 +1,42 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * EnrichedBoundary + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class EnrichedBoundary { + + @JsonProperty("id") + private String id; + + @JsonProperty("code") + @NotNull + private String code; + + @JsonProperty("boundaryType") + private String boundaryType; + + @JsonProperty("children") + @Valid + private List children = null; + + @JsonIgnore + private String parent = null; + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java b/health-services/census-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java new file mode 100644 index 00000000000..7a3e26f6595 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java @@ -0,0 +1,34 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.List; + +/** + * HierarchyRelation + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class HierarchyRelation { + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("hierarchyType") + private String hierarchyType = null; + + @JsonProperty("boundary") + @Valid + private List boundary = null; + + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignment.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignment.java new file mode 100644 index 00000000000..1cec6f46300 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignment.java @@ -0,0 +1,63 @@ +package digit.web.models.plan; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * PlanEmployeeAssignment + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignment { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(min = 2, max = 64) + private String planConfigurationId = null; + + @JsonProperty("employeeId") + @NotNull + @Size(min = 2, max = 64) + private String employeeId = null; + + @JsonProperty("role") + @NotNull + @Size(min = 2, max = 64) + private String role = null; + + @JsonProperty("jurisdiction") + @Valid + @NotEmpty + private List jurisdiction = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; +} diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentResponse.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentResponse.java new file mode 100644 index 00000000000..8e6e0260116 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentResponse.java @@ -0,0 +1,37 @@ +package digit.web.models.plan; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + + +/** + * PlanEmployeeAssignmentResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("PlanEmployeeAssignment") + @Valid + private List planEmployeeAssignment = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; +} + diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchCriteria.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchCriteria.java new file mode 100644 index 00000000000..6e38c1dad95 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchCriteria.java @@ -0,0 +1,50 @@ +package digit.web.models.plan; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * PlanEmployeeAssignmentSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentSearchCriteria { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @Size(min = 2, max = 100) + @NotNull + private String tenantId = null; + + @JsonProperty("employeeId") + private List employeeId = null; + + @JsonProperty("planConfigurationId") + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("role") + @Size(min = 2, max = 64) + private List role = null; + + @JsonProperty("jurisdiction") + @Valid + private List jurisdiction = null; + + @JsonProperty("active") + private Boolean active = null; +} diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchRequest.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchRequest.java new file mode 100644 index 00000000000..4a343fb8e45 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchRequest.java @@ -0,0 +1,29 @@ +package digit.web.models.plan; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanEmployeeAssignmentSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentSearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanEmployeeAssignmentSearchCriteria") + @Valid + private PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = null; +} diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityDTO.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityDTO.java new file mode 100644 index 00000000000..ce15f091cec --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityDTO.java @@ -0,0 +1,72 @@ +package digit.web.models.plan; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * Plan Facility DTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityDTO { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("facilityId") + @NotNull + @Size(max = 64) + private String facilityId = null; + + @JsonProperty("residingBoundary") + @NotNull + @Size(min = 1, max = 64) + private String residingBoundary = null; + + // Changed List to String to store as JSON + @JsonProperty("serviceBoundaries") + @NotNull + @Size(min = 1) + private String serviceBoundaries = null; // Store as JSON string + + @JsonProperty("initiallySetServiceBoundaries") + private List initiallySetServiceBoundaries; + + @JsonProperty("facilityName") + private String facilityName = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + @NotNull + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityRequestDTO.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityRequestDTO.java new file mode 100644 index 00000000000..6bae9ac51c2 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityRequestDTO.java @@ -0,0 +1,33 @@ +package digit.web.models.plan; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanFacilityRequestDTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityRequestDTO { + + @JsonProperty("RequestInfo") + @Valid + @NotNull + private RequestInfo requestInfo; + + @JsonProperty("PlanFacility") + @Valid + @NotNull + private PlanFacilityDTO planFacilityDTO; + +} diff --git a/health-services/census-service/src/main/resources/application.properties b/health-services/census-service/src/main/resources/application.properties new file mode 100644 index 00000000000..fcf43df5960 --- /dev/null +++ b/health-services/census-service/src/main/resources/application.properties @@ -0,0 +1,82 @@ +server.contextPath=/census-service +server.servlet.context-path=/census-service +management.endpoints.web.base-path=/ +server.port=8080 +app.timezone=UTC + +#DATABASE CONFIGURATION +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/censusDB +spring.datasource.username=postgres +spring.datasource.password=postgres + +#FLYWAY CONFIGURATION +spring.flyway.url=jdbc:postgresql://localhost:5432/censusDB +spring.flyway.user=postgres +spring.flyway.password=postgres +spring.flyway.table=public +spring.flyway.baseline-on-migrate=true +spring.flyway.outOfOrder=true +spring.flyway.locations=classpath:/db/migration/main +spring.flyway.enabled=false + +# KAFKA SERVER CONFIGURATIONS +kafka.config.bootstrap_server_config=localhost:9092 +spring.kafka.consumer.value-deserializer=org.egov.tracer.kafka.deserializer.HashMapDeserializer +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.group-id=census-serivce +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer +spring.kafka.listener.missing-topics-fatal=false +spring.kafka.consumer.properties.spring.json.use.type.headers=false +spring.kafka.producer.properties.max.request.size=3000000 + +# KAFKA CONSUMER CONFIGURATIONS +kafka.consumer.config.auto_commit=true +kafka.consumer.config.auto_commit_interval=100 +kafka.consumer.config.session_timeout=15000 +kafka.consumer.config.auto_offset_reset=earliest +# KAFKA PRODUCER CONFIGURATIONS +kafka.producer.config.retries_config=0 +kafka.producer.config.batch_size_config=16384 +kafka.producer.config.linger_ms_config=1 +kafka.producer.config.buffer_memory_config=33554432 + +#PERSISTER KAFKA TOPICS +census.create.topic=census-create-topic +census.update.topic=census-update-topic +census.bulk.update.topic=census-bulk-update-topic + +egov.sms.notification.topic=egov.core.notification.sms +kafka.topics.receipt.create=dss-collection + +#Boundary service urls +egov.boundary.service.host=https://unified-dev.digit.org +egov.boundary.relationship.search.endpoint=/boundary-service/boundary-relationships/_search +egov.boundary.hierarchy.search.endpoint=/boundary-service/boundary-hierarchy-definition/_search + +#Plan service urls +egov.plan.service.host=https://unified-dev.digit.org +egov.plan.employee.assignment.search.endpoint=/plan-service/employee/_search + +# Workflow +egov.workflow.host=https://unified-dev.digit.org +egov.workflow.transition.path=/egov-workflow-v2/egov-wf/process/_transition +egov.business.service.search.endpoint=/egov-workflow-v2/egov-wf/businessservice/_search +workflow.initiate.action=INITIATE +workflow.intermediate.action=EDIT_AND_SEND_FOR_APPROVAL,APPROVE +workflow.send.back.actions=SEND_BACK_FOR_CORRECTION + + +#Pagination config +census.default.offset=0 +census.default.limit=10 + +resource.config.consumer.census.create.topic=resource-census-create-topic +resource.config.consumer.census.update.topic=resource-census-update-topic + +plan.facility.update.topic=update-plan-facility + +#Roles for census +allowed.census.roles={'POPULATION_DATA_APPROVER','ROOT_POPULATION_DATA_APPROVER'} +workflow.restricted.roles={'ROOT_FACILITY_CATCHMENT_MAPPER','FACILITY_CATCHMENT_MAPPER'} \ No newline at end of file diff --git a/health-services/census-service/src/main/resources/db/Dockerfile b/health-services/census-service/src/main/resources/db/Dockerfile new file mode 100644 index 00000000000..f38638a269f --- /dev/null +++ b/health-services/census-service/src/main/resources/db/Dockerfile @@ -0,0 +1,9 @@ +FROM egovio/flyway:10.7.1 + +COPY ./migration/main /flyway/sql + +COPY migrate.sh /usr/bin/migrate.sh + +RUN chmod +x /usr/bin/migrate.sh + +ENTRYPOINT ["/usr/bin/migrate.sh"] diff --git a/health-services/resource-estimation-service/src/main/resources/db/migrate.sh b/health-services/census-service/src/main/resources/db/migrate.sh similarity index 67% rename from health-services/resource-estimation-service/src/main/resources/db/migrate.sh rename to health-services/census-service/src/main/resources/db/migrate.sh index 43960b25cdb..c58d6f91e3f 100644 --- a/health-services/resource-estimation-service/src/main/resources/db/migrate.sh +++ b/health-services/census-service/src/main/resources/db/migrate.sh @@ -1,3 +1,3 @@ #!/bin/sh -flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true -ignoreMissingMigrations=true migrate \ No newline at end of file +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true migrate \ No newline at end of file diff --git a/health-services/census-service/src/main/resources/db/migration/main/V20240925155908__census_create_ddl.sql b/health-services/census-service/src/main/resources/db/migration/main/V20240925155908__census_create_ddl.sql new file mode 100644 index 00000000000..cf80c461292 --- /dev/null +++ b/health-services/census-service/src/main/resources/db/migration/main/V20240925155908__census_create_ddl.sql @@ -0,0 +1,36 @@ +-- Table: census +CREATE TABLE census ( + id character varying(64) NOT NULL, + tenant_id character varying(64) NOT NULL, + hierarchy_type character varying(64) NOT NULL, + boundary_code character varying(64) NOT NULL, + type character varying(64) NOT NULL, + total_population bigint NOT NULL, + effective_from bigint NOT NULL, + effective_to bigint, + source character varying(255) NOT NULL, + status character varying(255), + assignee character varying(255), + facility_assigned boolean, + boundary_ancestral_path TEXT NOT NULL, + additional_details JSONB, + created_by character varying(64) NOT NULL, + created_time bigint NOT NULL, + last_modified_by character varying(64) NOT NULL, + last_modified_time bigint NOT NULL, + CONSTRAINT uk_census_id PRIMARY KEY (id) +); + +-- Table: population_by_demographics +CREATE TABLE population_by_demographics ( + id character varying(64), + census_id character varying(64), + demographic_variable character varying(64), + population_distribution JSONB, + created_by character varying(64), + created_time bigint, + last_modified_by character varying(64), + last_modified_time bigint, + CONSTRAINT uk_population_by_demographics_id PRIMARY KEY (id), + FOREIGN KEY (census_id) REFERENCES census(id) +); diff --git a/health-services/census-service/src/main/resources/db/migration/main/V20241105152700__census_additional_field_create_ddl.sql b/health-services/census-service/src/main/resources/db/migration/main/V20241105152700__census_additional_field_create_ddl.sql new file mode 100644 index 00000000000..9887f73656f --- /dev/null +++ b/health-services/census-service/src/main/resources/db/migration/main/V20241105152700__census_additional_field_create_ddl.sql @@ -0,0 +1,12 @@ +-- Table: additional_field +CREATE TABLE additional_field ( + id character varying(64) NOT NULL, + census_id character varying(64) NOT NULL, + "key" character varying(64) NOT NULL, + "value" numeric(12,2) NOT NULL, + show_on_ui boolean DEFAULT true NOT NULL, + editable boolean DEFAULT true NOT NULL, + "order" bigint NOT NULL, + CONSTRAINT uk_additional_field_id PRIMARY KEY (id), + FOREIGN KEY (census_id) REFERENCES census(id) +); diff --git a/health-services/census-service/src/main/resources/db/migration/main/V20241126120700__alter_census_assignee_create_ddl.sql b/health-services/census-service/src/main/resources/db/migration/main/V20241126120700__alter_census_assignee_create_ddl.sql new file mode 100644 index 00000000000..7d271361aae --- /dev/null +++ b/health-services/census-service/src/main/resources/db/migration/main/V20241126120700__alter_census_assignee_create_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE census ALTER COLUMN assignee TYPE TEXT; \ No newline at end of file diff --git a/health-services/census-service/src/main/resources/start.sh b/health-services/census-service/src/main/resources/start.sh new file mode 100644 index 00000000000..36eccc0ae97 --- /dev/null +++ b/health-services/census-service/src/main/resources/start.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +if [[ -z "${JAVA_OPTS}" ]];then +export JAVA_OPTS="-Xmx64m -Xms64m" +fi + +if [ x"${JAVA_ENABLE_DEBUG}" != x ] && [ "${JAVA_ENABLE_DEBUG}" != "false" ]; then +java_debug_args="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${JAVA_DEBUG_PORT:-5005}" +fi + +exec java ${java_debug_args} ${JAVA_OPTS} ${JAVA_ARGS} -jar /opt/egov/*.jar \ No newline at end of file diff --git a/health-services/census-service/src/test/java/digit/TestConfiguration.java b/health-services/census-service/src/test/java/digit/TestConfiguration.java new file mode 100644 index 00000000000..570236cfc94 --- /dev/null +++ b/health-services/census-service/src/test/java/digit/TestConfiguration.java @@ -0,0 +1,16 @@ +package digit; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; + +import static org.mockito.Mockito.mock; + +@Configuration +public class TestConfiguration { + @Bean + @SuppressWarnings("unchecked") + public KafkaTemplate kafkaTemplate() { + return mock(KafkaTemplate.class); + } +} \ No newline at end of file diff --git a/health-services/census-service/src/test/java/digit/web/controllers/CensusControllerTest.java b/health-services/census-service/src/test/java/digit/web/controllers/CensusControllerTest.java new file mode 100644 index 00000000000..df3d8c23267 --- /dev/null +++ b/health-services/census-service/src/test/java/digit/web/controllers/CensusControllerTest.java @@ -0,0 +1,69 @@ +package digit.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.service.CensusService; +import digit.web.models.CensusRequest; +import digit.web.models.CensusSearchRequest; +import org.junit.Test; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import digit.TestConfiguration; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for CensusApiController + */ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(CensusController.class) +@Import(TestConfiguration.class) +public class CensusControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private JdbcTemplate jdbcTemplate; + + @MockBean + private CensusService service; + + @Autowired + private ObjectMapper objectMapper; + + + @Test + public void censusCreatePostSuccess() throws Exception { + CensusRequest request = CensusRequest.builder().build(); + mockMvc.perform(post("/_create").contentType(MediaType + .APPLICATION_JSON_UTF8).content(objectMapper.writeValueAsString(request))) + .andExpect(status().isAccepted()); + } + + @Test + public void censusSearchPostSuccess() throws Exception { + CensusSearchRequest request = CensusSearchRequest.builder().build(); + mockMvc.perform(post("/_search").contentType(MediaType + .APPLICATION_JSON_UTF8).content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()); + } + + @Test + public void censusUpdatePostSuccess() throws Exception { + CensusRequest request = CensusRequest.builder().build(); + mockMvc.perform(post("/_update").contentType(MediaType + .APPLICATION_JSON_UTF8).content(objectMapper.writeValueAsString(request))) + .andExpect(status().isAccepted()); + } + +} diff --git a/health-services/plan-service/CHANGELOG.md b/health-services/plan-service/CHANGELOG.md index 650d79eae57..a73439d7658 100644 --- a/health-services/plan-service/CHANGELOG.md +++ b/health-services/plan-service/CHANGELOG.md @@ -1,10 +1,38 @@ # Changelog All notable changes to this module will be documented in this file. -## 1.0.0 - 2024-06-24 -#### Plan Service - 1. Plan Service manages: validation of plans, plan search, plan create, plan update. - 2. Validation of plan: Plan service validates plan request before it takes action on it like update or create. - 3. Plan Create: Plan service creates a plan after successful validation is done. It sends create request on topic to create plan. - 4. Plan Update : Plan service creates a plan after successful validation is done. It sends update request on topic to resource estimation service to further process. - 5. Plan Search: This enables to search plan based on provided search string. \ No newline at end of file +## 1.0.0 - 2024-12-03 +### Plan Service + +##### Plan Configuration + +1. Validation of Plan Configuration: Validates all plan configuration requests against MDMS and Project Factory before processing the requests. +2. Plan Configuration Create: Validates and enriches new plan configurations before publishing them to the Kafka topic for asynchronous processing. +3. Plan Configuration Update: Updates existing plan configurations post-validation and enrichment by pushing requests to the Kafka update topic. +4. Plan Configuration Search: Facilitates searching for plan configurations using the provided search criteria. +5. Resource Generator Consumer: Listens to resource generator plan configuration update topic to update plan configuration. + +#### Plan + +1. Plan manages: validation of plans, plan search, plan create, plan update. +2. Validation of plan: Plan service validates plan request before it takes action on it like update or create. +3. Plan Create: Plan service creates a plan after successful validation is done. It sends create request on topic to create plan. +4. Plan Update : Plan service creates a plan after successful validation is done. It sends update request on topic to resource estimation service to further process. +5. Plan Search: This enables to search plan based on provided search string. +6. Plan Bulk Update: Allows updating multiple plans in a single operation after validation. +7. Resource Generator Consumer: Listens to resource plan create topic to trigger the creation of new plans. + +#### Plan Facility + +1. Validation: Validates plan facility requests against MDMS, Facility Service and Project Factory before processing the requests. +2. Plan Facility Create: Creates a plan facility after validation and enrichment, pushing the create request to the designated kafka topic. +3. Plan Facility Update: Updates existing facilities post-validation by pushing update requests to the Kafka topic. Also sends the update request to Census service for facility mapping. +4. Plan Facility Search: Searches Plan Facility for the provided search criteria. +5. Project Factory Consumer: Listens to project factory consumer to enrich and create new plan facility. + +#### Plan Employee Assignment + +1. Validation: Validates plan employee assignment requests against MDMS, User service and Project Factory before processing the requests. +2. Plan Employee Assignment Create: Assigns employees to plans post-validation and enrichment, considering roles and jurisdictions by pushing request to create kafka topic. +3. Plan Employee Assignment Update: Updates existing assignments after validation, publishing the changes to the designated Kafka update topic. +4. Plan Employee Assignment Search: Enables searching for employee assignments using provided search criteria. \ No newline at end of file diff --git a/health-services/plan-service/pom.xml b/health-services/plan-service/pom.xml index ce6a2dff717..c41f44a9f05 100644 --- a/health-services/plan-service/pom.xml +++ b/health-services/plan-service/pom.xml @@ -89,6 +89,17 @@ junit test + + org.egov.services + services-common + 2.9.0-SNAPSHOT + compile + + + org.apache.commons + commons-text + 1.10.0 + diff --git a/health-services/plan-service/src/main/java/digit/Main.java b/health-services/plan-service/src/main/java/digit/Main.java index 9ccda08d54e..4c49611bebd 100644 --- a/health-services/plan-service/src/main/java/digit/Main.java +++ b/health-services/plan-service/src/main/java/digit/Main.java @@ -9,7 +9,7 @@ @Import({ TracerConfiguration.class }) @SpringBootApplication -@ComponentScan(basePackages = { "digit", "digit.web.controllers" , "digit.config"}) +@ComponentScan(basePackages = { "digit", "digit.web.controllers" , "digit.config", "org.egov.common.utils"}) public class Main { public static void main(String[] args) throws Exception { diff --git a/health-services/plan-service/src/main/java/digit/config/Configuration.java b/health-services/plan-service/src/main/java/digit/config/Configuration.java index 7cf4b3549f7..110be35646a 100644 --- a/health-services/plan-service/src/main/java/digit/config/Configuration.java +++ b/health-services/plan-service/src/main/java/digit/config/Configuration.java @@ -1,16 +1,13 @@ package digit.config; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.*; import org.egov.tracer.config.TracerConfiguration; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.stereotype.Component; -import java.util.TimeZone; +import java.util.List; +import java.util.Map; @Component @Data @@ -21,6 +18,13 @@ @Getter public class Configuration { + //Role Map + @Value("#{${role.map}}") + public Map roleMap; + + @Value("${plan.estimation.approver.roles}") + public List planEstimationApproverRoles; + //MDMS @Value("${egov.mdms.host}") private String mdmsHost; @@ -28,6 +32,32 @@ public class Configuration { @Value("${egov.mdms.search.endpoint}") private String mdmsEndPoint; + @Value("${egov.mdms.search.v2.endpoint}") + private String mdmsV2EndPoint; + + //Project Factory + @Value("${egov.project.factory.host}") + private String projectFactoryHost; + + @Value("${egov.project.factory.search.endpoint}") + private String projectFactorySearchEndPoint; + + //User Service + @Value("${egov.user.service.host}") + private String userServiceHost; + + @Value("${egov.user.search.endpoint}") + private String userSearchEndPoint; + + // Boundary Service + @Value("${egov.boundary.service.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.relationship.search.endpoint}") + private String boundaryRelationshipSearchEndpoint; + + @Value("${egov.boundary.hierarchy.search.endpoint}") + private String boundaryHierarchySearchEndpoint; //Persister Topic @Value("${plan.configuration.create.topic}") @@ -36,16 +66,64 @@ public class Configuration { @Value("${plan.configuration.update.topic}") private String planConfigUpdateTopic; + @Value("${plan.employee.assignment.create.topic}") + private String planEmployeeAssignmentCreateTopic; + + @Value("${plan.employee.assignment.update.topic}") + private String planEmployeeAssignmentUpdateTopic; + @Value("${plan.create.topic}") private String planCreateTopic; @Value("${plan.update.topic}") private String planUpdateTopic; + @Value("${plan.bulk.update.topic}") + private String planBulkUpdateTopic; + + @Value("${plan.facility.create.topic}") + private String planFacilityCreateTopic; + + @Value("${plan.facility.update.topic}") + private String planFacilityUpdateTopic; + @Value("${plan.default.offset}") private Integer defaultOffset; @Value("${plan.default.limit}") private Integer defaultLimit; + //Census + @Value("${egov.census.host}") + private String censusHost; + + @Value("${egov.census.search.endpoint}") + private String censusSearchEndPoint; + + //Facility + @Value("${egov.facility.host}") + private String facilityHost; + + @Value("${egov.facility.search.endpoint}") + private String facilitySearchEndPoint; + + //Workflow + @Value("${egov.workflow.host}") + private String wfHost; + + @Value("${egov.workflow.transition.path}") + private String wfTransitionPath; + + @Value("${egov.business.service.search.endpoint}") + private String businessServiceSearchEndpoint; + + @Value("${workflow.initiate.action}") + private List wfInitiateActions; + + @Value("${workflow.intermediate.action}") + private List wfIntermediateActions; + + @Value("${workflow.send.back.actions}") + private List wfSendBackActions; + } diff --git a/health-services/plan-service/src/main/java/digit/config/ServiceConstants.java b/health-services/plan-service/src/main/java/digit/config/ServiceConstants.java index 2266c82de93..a2b9696b482 100644 --- a/health-services/plan-service/src/main/java/digit/config/ServiceConstants.java +++ b/health-services/plan-service/src/main/java/digit/config/ServiceConstants.java @@ -12,55 +12,118 @@ public class ServiceConstants { public static final String ERROR_WHILE_FETCHING_FROM_MDMS = "Exception occurred while fetching category lists from mdms: "; + public static final String ERROR_WHILE_FETCHING_FROM_USER_SERVICE = "Exception occurred while fetching user details from user service: "; + + public static final String ERROR_WHILE_FETCHING_FROM_PROJECT_FACTORY = "Exception occurred while fetching campaign details from project factory: "; + + public static final String ERROR_WHILE_FETCHING_FROM_CENSUS = "Exception occurred while fetching records from census: "; + + public static final String ERROR_WHILE_FETCHING_BOUNDARY_DETAILS = "Exception occurred while fetching boundary relationship from boundary service: "; + + public static final String ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS = "Exception occurred while fetching boundary hierarchy details from boundary service: "; + + public static final String ERROR_WHILE_FETCHING_DATA_FROM_HRMS = "Exception occurred while fetching employee from hrms: "; + public static final String RES_MSG_ID = "uief87324"; public static final String SUCCESSFUL = "successful"; public static final String FAILED = "failed"; + public static final String ROOT_PREFIX = "ROOT"; + public static final String USERINFO_MISSING_CODE = "USERINFO_MISSING"; public static final String USERINFO_MISSING_MESSAGE = "UserInfo is missing in Request Info "; public static final String ASSUMPTION_VALUE_NOT_FOUND_CODE = "ASSUMPTION_VALUE_NOT_FOUND"; - public static final String ASSUMPTION_VALUE_NOT_FOUND_MESSAGE = "Operation's Assumption value not found in active assumptions list "; - - public static final String FILESTORE_ID_INVALID_CODE = "FILESTORE_ID_INVALID"; - public static final String FILESTORE_ID_INVALID_MESSAGE = "Resource mapping does not have a Valid File Store Id "; + public static final String ASSUMPTION_VALUE_NOT_FOUND_MESSAGE = "Operation's Assumption value is not present in allowed columns, previous outputs, or active Assumption Keys "; public static final String ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_CODE = "ASSUMPTION_KEY_NOT_FOUND_IN_MDMS"; - public static final String ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE = "Assumption Key is not present in MDMS"; + public static final String ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE = "Assumption Key is not present in MDMS - "; + + public static final String DUPLICATE_ASSUMPTION_KEY_CODE = "DUPLICATE_ASSUMPTION_KEY"; + public static final String DUPLICATE_ASSUMPTION_KEY_MESSAGE = "Duplicate Assumption key found : "; + + public static final String VEHICLE_ID_NOT_FOUND_IN_MDMS_CODE = "VEHICLE_ID_NOT_FOUND_IN_MDMS"; + public static final String VEHICLE_ID_NOT_FOUND_IN_MDMS_MESSAGE = "Vehicle Id is not present in MDMS"; + + public static final String VEHICLE_IDS_INVALID_DATA_TYPE_CODE = "VEHICLE_IDS_INVALID_DATA_TYPE"; + public static final String VEHICLE_IDS_INVALID_DATA_TYPE_MESSAGE = "Vehicle IDs should be a list of strings."; public static final String TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_CODE = "TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS"; - public static final String TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_MESSAGE = "Template Identifier is not present in MDMS"; + public static final String TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_MESSAGE = "Template Identifier is not present in MDMS "; public static final String REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_CODE = "REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND"; - public static final String REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_MESSAGE = "Required Template Identifier is not present in Files"; + public static final String REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_MESSAGE = "Required Template Identifier is not present in Files "; public static final String ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_CODE = "ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER"; - public static final String ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_MESSAGE = "Only one file of the required template identifier should be present."; + public static final String ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_MESSAGE = "Only one file of the required template identifier should be present "; public static final String INPUT_KEY_NOT_FOUND_CODE = "INPUT_KEY_NOT_FOUND"; - public static final String INPUT_KEY_NOT_FOUND_MESSAGE = "Operation's Input key not present in MDMS"; - - public static final String LOCALITY_NOT_PRESENT_IN_MAPPED_TO_CODE = "LOCALITY_NOT_PRESENT_IN_MAPPED_TO"; - public static final String LOCALITY_NOT_PRESENT_IN_MAPPED_TO_MESSAGE = "Resource Mapping's MappedTo must contain 'Locality'"; - - public static final String DUPLICATE_MAPPED_TO_VALIDATION_ERROR_CODE = "DUPLICATE_MAPPED_TO_VALIDATION_ERROR"; - public static final String DUPLICATE_MAPPED_TO_VALIDATION_ERROR_MESSAGE = "Duplicate MappedTo found in Resource Mapping"; - - public static final String TENANT_NOT_FOUND_IN_MDMS_CODE = "TENANT_ID_NOT_FOUND_IN_MDMS"; - public static final String TENANT_NOT_FOUND_IN_MDMS_MESSAGE = "Tenant Id is not present in MDMS"; + public static final String INPUT_KEY_NOT_FOUND_MESSAGE = "Operation's Input key is not present in allowed columns or previous outputs - "; public static final String TENANT_ID_EMPTY_CODE = "TENANT_ID_EMPTY"; public static final String TENANT_ID_EMPTY_MESSAGE = "Tenant Id cannot be empty, TenantId should be present"; + public static final String PLAN_CONFIG_ID_EMPTY_CODE = "PLAN_CONFIG_ID_EMPTY"; + public static final String PLAN_CONFIG_ID_EMPTY_MESSAGE = "Plan config Id cannot be empty."; + public static final String NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE = "NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT"; public static final String NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE = "Invalid or incorrect TenantId. No mdms data found for provided Tenant."; + public static final String INVALID_EMPLOYEE_ID_CODE = "INVALID_EMPLOYEE_ID"; + public static final String INVALID_EMPLOYEE_ID_MESSAGE = "Invalid or incorrect employee id."; + + public static final String NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE = "NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID"; + public static final String NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE = "Invalid or incorrect campaign id. No campaign details found for provided campaign id."; + + public static final String NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_CODE = "NO_CENSUS_FOUND_FOR_GIVEN_DETAILS"; + public static final String NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_MESSAGE = "Census records does not exists for the given details: "; + + + public static final String INVALID_ROOT_EMPLOYEE_JURISDICTION_CODE = "INVALID_ROOT_EMPLOYEE_JURISDICTION"; + public static final String INVALID_ROOT_EMPLOYEE_JURISDICTION_MESSAGE = "The root employee's jurisdiction should be at highest hierarchy"; + + public static final String INVALID_EMPLOYEE_JURISDICTION_CODE = "INVALID_EMPLOYEE_JURISDICTION"; + public static final String INVALID_EMPLOYEE_JURISDICTION_MESSAGE = "The employee's jurisdiction can't be at highest or lowest hierarchy"; + + public static final String INVALID_JURISDICTION_CODE = "INVALID_JURISDICTION"; + public static final String INVALID_JURISDICTION_MESSAGE = "The employee's jurisdiction provided is invalid"; + + public static final String INVALID_HIERARCHY_LEVEL_CODE = "INVALID_HIERARCHY_LEVEL"; + public static final String INVALID_HIERARCHY_LEVEL_MESSAGE = "The hierarchy level provided is invalid"; + + public static final String INVALID_EMPLOYEE_ROLE_CODE = "INVALID_EMPLOYEE_ROLE"; + public static final String INVALID_EMPLOYEE_ROLE_MESSAGE = "The employee's role provided is invalid"; + public static final String SEARCH_CRITERIA_EMPTY_CODE = "SEARCH_CRITERIA_EMPTY"; public static final String SEARCH_CRITERIA_EMPTY_MESSAGE = "Search criteria cannot be empty"; public static final String INVALID_PLAN_CONFIG_ID_CODE = "INVALID_PLAN_CONFIG_ID"; public static final String INVALID_PLAN_CONFIG_ID_MESSAGE = "Plan config id provided is invalid"; + public static final String INVALID_PLAN_EMPLOYEE_ASSIGNMENT_CODE = "INVALID_PLAN_EMPLOYEE_ASSIGNMENT"; + public static final String INVALID_PLAN_EMPLOYEE_ASSIGNMENT_MESSAGE = "Plan employee assignment to be updated doesn't exists"; + + public static final String PLAN_CONFIGURATION_ALREADY_EXISTS_CODE = "PLAN_CONFIGURATION_ALREADY_EXISTS"; + public static final String PLAN_CONFIGURATION_ALREADY_EXISTS_MESSAGE = "Plan Configuration for the provided name and campaign id already exists"; + + public static final String PLAN_EMPLOYEE_ASSIGNMENT_ALREADY_EXISTS_CODE = "PLAN_EMPLOYEE_ASSIGNMENT_ALREADY_EXISTS"; + public static final String PLAN_EMPLOYEE_ASSIGNMENT_ALREADY_EXISTS_MESSAGE = "Plan employee assignment for the provided details already exists"; + + public static final String PLAN_FACILITY_LINKAGE_ALREADY_EXISTS_CODE = "PLAN_FACILITY_LINKAGE_ALREADY_EXISTS"; + public static final String PLAN_FACILITY_LINKAGE_ALREADY_EXISTS_MESSAGE = "Plan facility linkage for the provided facilityId and planConfigId already exists"; + + public static final String PLAN_EMPLOYEE_ASSIGNMENT_ID_EMPTY_CODE = "PLAN_EMPLOYEE_ASSIGNMENT_ID_EMPTY"; + public static final String PLAN_EMPLOYEE_ASSIGNMENT_ID_EMPTY_MESSAGE = "Plan employee assignment id cannot be empty"; + + public static final String PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_CODE = "PLAN_EMPLOYEE_ASSIGNMENT_FOR_BOUNDARY_NOT_FOUND"; + public static final String PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_MESSAGE = "No plan-employee assignment found for the provided boundary - "; + + public static final String JURISDICTION_NOT_FOUND_CODE = "JURISDICTION_NOT_FOUND"; + public static final String JURISDICTION_NOT_FOUND_MESSAGE = "Employee doesn't have the jurisdiction to take action for the provided locality."; + + public static final String NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE = "NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE"; + public static final String NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE = "Invalid or incorrect boundaryCode. No boundary data found."; + public static final String METRIC_NOT_FOUND_IN_MDMS_CODE = "METRIC_NOT_FOUND_IN_MDMS"; public static final String METRIC_NOT_FOUND_IN_MDMS_MESSAGE = "Metric key not found in MDMS"; @@ -73,26 +136,119 @@ public class ServiceConstants { public static final String JSONPATH_ERROR_CODE = "JSONPATH_ERROR"; public static final String JSONPATH_ERROR_MESSAGE = "Failed to parse mdms response with given Jsonpath" ; - public static final String BOUNDARY_CODE_MAPPING_NOT_FOUND_CODE = "BOUNDARY_CODE_MAPPING_NOT_FOUND"; - public static final String BOUNDARY_CODE_MAPPING_NOT_FOUND_MESSAGE = "Boundary Code Mapping is required column is not found."; + public static final String NAME_VALIDATION_LIST_EMPTY_CODE = "NAME_VALIDATION_LIST_EMPTY"; + public static final String NAME_VALIDATION_LIST_EMPTY_MESSAGE = "Name Validation list from MDMS is empty"; + + public static final String NAME_VALIDATION_FAILED_CODE = "NAME_VALIDATION_FAILED"; + public static final String NAME_VALIDATION_FAILED_MESSAGE = "Name Validation failed"; + + public static final String INVALID_PLAN_ID_CODE = "INVALID_PLAN_ID"; + public static final String INVALID_PLAN_ID_MESSAGE = "Plan id provided is invalid"; + + public static final String CYCLIC_ACTIVITY_DEPENDENCY_CODE = "CYCLIC_ACTIVITY_DEPENDENCY"; + public static final String CYCLIC_ACTIVITY_DEPENDENCY_MESSAGE = "Cyclic activity dependency found"; + + public static final String INVALID_ACTIVITY_DEPENDENCY_CODE = "INVALID_ACTIVITY_DEPENDENCY"; + public static final String INVALID_ACTIVITY_DEPENDENCY_MESSAGE = "Activity dependency is invalid"; + + public static final String ACTIVITIES_CANNOT_BE_NULL_CODE = "ACTIVITIES_CANNOT_BE_NULL"; + public static final String ACTIVITIES_CANNOT_BE_NULL_MESSAGE = "Activities list in Plan cannot be null"; + + public static final String DUPLICATE_ACTIVITY_CODES = "DUPLICATE_ACTIVITY_CODES"; + public static final String DUPLICATE_ACTIVITY_CODES_MESSAGE = "Activity codes within the plan should be unique"; + + public static final String PLAN_ACTIVITIES_MANDATORY_CODE = "PLAN_ACTIVITIES_MANDATORY"; + public static final String PLAN_ACTIVITIES_MANDATORY_MESSAGE = "Activities are mandatory if execution plan id is not provided"; + + public static final String PLAN_ACTIVITIES_NOT_ALLOWED_CODE = "PLAN_ACTIVITIES_NOT_ALLOWED"; + public static final String PLAN_ACTIVITIES_NOT_ALLOWED_MESSAGE = "Activities are not allowed if execution plan id is provided"; + + public static final String INVALID_ACTIVITY_DATES_CODE = "INVALID_ACTIVITY_DATES"; + public static final String INVALID_ACTIVITY_DATES_MESSAGE = "Planned end date cannot be before planned start date"; + + public static final String PLAN_RESOURCES_MANDATORY_CODE = "PLAN_RESOURCES_MANDATORY"; + public static final String PLAN_RESOURCES_MANDATORY_MESSAGE = "Resources are mandatory if plan configuration id is not provided"; + + public static final String INVALID_RESOURCE_ACTIVITY_LINKAGE_CODE = "INVALID_RESOURCE_ACTIVITY_LINKAGE"; + public static final String INVALID_RESOURCE_ACTIVITY_LINKAGE_MESSAGE = "Resource-Activity linkage is invalid"; + + public static final String INVALID_TARGET_ACTIVITY_LINKAGE_CODE = "INVALID_TARGET_ACTIVITY_LINKAGE"; + public static final String INVALID_TARGET_ACTIVITY_LINKAGE_MESSAGE = "Target-Activity linkage is invalid"; + + public static final String DUPLICATE_TARGET_UUIDS_CODE = "DUPLICATE_TARGET_UUIDS"; + public static final String DUPLICATE_TARGET_UUIDS_MESSAGE = "Target UUIDs should be unique"; + + public static final String DUPLICATE_RESOURCE_UUIDS_CODE = "DUPLICATE_RESOURCE_UUIDS"; + public static final String DUPLICATE_RESOURCE_UUIDS_MESSAGE = "Resource UUIDs should be unique"; + + public static final String DUPLICATE_ACTIVITY_UUIDS_CODE = "DUPLICATE_ACTIVITY_UUIDS"; + public static final String DUPLICATE_ACTIVITY_UUIDS_MESSAGE = "Activity UUIDs should be unique"; + + public static final String ADDITIONAL_DETAILS_MISSING_CODE = "ADDITIONAL_DETAILS_MISSING"; + public static final String ADDITIONAL_DETAILS_MISSING_MESSAGE = "Additional details are missing in the plan configuration request."; + + public static final String PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE = "PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT"; + public static final String PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE = "Key is not present in json object - "; + + public static final String ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE = "ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS"; + public static final String ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE = "Exception occurred while updating additional details : "; + + public static final String WORKFLOW_INTEGRATION_ERROR_CODE = "WORKFLOW_INTEGRATION_ERROR"; + public static final String WORKFLOW_INTEGRATION_ERROR_MESSAGE = "Exception occured while integrating with workflow : "; + + public static final String PROCESS_INSTANCE_NOT_FOUND_CODE = "PROCESS_INSTANCE_NOT_FOUND"; + public static final String PROCESS_INSTANCE_NOT_FOUND_MESSAGE = "No process instance found with businessId: "; + + public static final String FILES_NOT_FOUND_CODE = "FILES_NOT_FOUND"; + public static final String FILES_NOT_FOUND_MESSAGE = "Files are not present in Plan Configuration."; + + public static final String ASSUMPTIONS_NOT_FOUND_CODE = "ASSUMPTIONS_NOT_FOUND"; + public static final String ASSUMPTIONS_NOT_FOUND_MESSAGE = "Assumptions are not present in Plan Configuration."; + + public static final String OPERATIONS_NOT_FOUND_CODE = "OPERATIONS_NOT_FOUND"; + public static final String OPERATIONS_NOT_FOUND_MESSAGE = "Operations are not present in Plan Configuration."; + + public static final String NO_BUSINESS_SERVICE_DATA_FOUND_CODE = "NO_BUSINESS_SERVICE_DATA_FOUND"; + public static final String NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE = "Invalid or incorrect businessService. No business service data found."; //mdms constants public static final String MDMS_PLAN_MODULE_NAME = "hcm-microplanning"; + public static final String MDMS_ADMIN_CONSOLE_MODULE_NAME = "HCM-ADMIN-CONSOLE"; + public static final String MDMS_MASTER_HIERARCHY_CONFIG = "hierarchyConfig"; + public static final String MDMS_MASTER_HIERARCHY_SCHEMA = "HierarchySchema"; public static final String MDMS_MASTER_ASSUMPTION = "HypothesisAssumptions"; public static final String MDMS_MASTER_UPLOAD_CONFIGURATION = "UploadConfiguration"; public static final String MDMS_MASTER_RULE_CONFIGURE_INPUTS = "RuleConfigureInputs"; public static final String MDMS_MASTER_SCHEMAS = "Schemas"; public static final String MDMS_MASTER_METRIC = "Metric"; public static final String MDMS_MASTER_UOM = "Uom"; + public static final String MDMS_MASTER_NAME_VALIDATION= "MicroplanNamingRegex"; + public static final String MDMS_SCHEMA_ADMIN_SCHEMA = "adminSchema"; + public static final String BOUNDARY = "boundary"; + public static final String HIERARCHY_TYPE = "hierarchyType"; + + //MDMS field Constants + public static final String PROPERTIES = "properties"; + public static final String NUMBER_PROPERTIES = "numberProperties"; + public static final String STRING_PROPERTIES = "stringProperties"; + public static final String NAME = "name"; + + public static final String MICROPLAN_PREFIX = "MP-"; + + public static final String JSON_ROOT_PATH = "$."; public static final String DOT_SEPARATOR = "."; public static final String DOT_REGEX = "\\."; + public static final String PIPE_REGEX = "\\|"; + public static final String FILTER_CODE = "$.*.code"; public static final String FILTER_ID = "$.*.id"; + public static final String FILTER_TO_GET_ALL_IDS = "*.id"; + public static final String FILTER_DATA = "$.*.data"; public static final String LOCALITY_CODE = "Locality"; @@ -108,6 +264,114 @@ public class ServiceConstants { public static final String MDMS_SCHEMA_PROPERTIES_IS_RULE_CONFIGURE_INPUT = "isRuleConfigureInputs"; public static final String MDMS_SCHEMA_PROPERTIES_IS_REQUIRED = "isRequired"; + + public static final String MDMS_SCHEMA_VEHICLE_DETAILS = "VehicleDetails"; + public static final String BOUNDARY_CODE = "boundaryCode"; + public static final String FILTER_ALL_ASSUMPTIONS = ".assumptionCategories[*].assumptions[*]"; + + public static final String HIERARCHY_CONFIG_FOR_MICROPLAN = "[?(@.type == 'microplan')]"; + + public static final String HIGHEST_HIERARCHY_FIELD_FOR_MICROPLAN = "highestHierarchy"; + + public static final String LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN = "lowestHierarchy"; + + public static final String NAME_VALIDATION_DATA = "Data"; + + // Constants for constructing logical expressions or queries + public static final String AND = " && "; + public static final String EQUALS = " == "; + public static final String SINGLE_QUOTE = "'"; + + // JSON field constants for campaign details + public static final String JSON_FIELD_CAMPAIGN_TYPE = "campaignType"; + public static final String JSON_FIELD_DISTRIBUTION_PROCESS = "DistributionProcess"; + public static final String JSON_FIELD_REGISTRATION_PROCESS = "RegistrationProcess"; + public static final String JSON_FIELD_RESOURCE_DISTRIBUTION_STRATEGY_CODE = "resourceDistributionStrategyCode"; + public static final String JSON_FIELD_IS_REGISTRATION_AND_DISTRIBUTION_TOGETHER = "isRegistrationAndDistributionHappeningTogetherOrSeparately"; + public static final String JSON_FIELD_VEHICLE_ID = "vehicleIds"; + + // JSON path constants for campaign details + public static final String JSONPATH_FILTER_PREFIX = "[?("; + public static final String JSONPATH_FILTER_SUFFIX = ")]"; + public static final String JSON_PATH_FILTER_CAMPAIGN_TYPE = "@.campaignType"; + public static final String JSON_PATH_FILTER_DISTRIBUTION_PROCESS = "@.DistributionProcess"; + public static final String JSON_PATH_FILTER_REGISTRATION_PROCESS = "@.RegistrationProcess"; + public static final String JSON_PATH_FILTER_RESOURCE_DISTRIBUTION_STRATEGY_CODE = "@.resourceDistributionStrategyCode"; + public static final String JSON_PATH_FILTER_IS_REGISTRATION_AND_DISTRIBUTION_TOGETHER = "@.isRegistrationAndDistributionHappeningTogetherOrSeparately"; + + // Workflow Constants + public static final String PLAN_CONFIGURATION_BUSINESS_SERVICE = "PLAN_CONFIGURATION"; + + public static final String PLAN_ESTIMATION_BUSINESS_SERVICE = "PLAN_ESTIMATION"; + + public static final String MODULE_NAME_VALUE = "plan-service"; + + public static final String DRAFT_STATUS = "DRAFT"; + + public static final String SETUP_COMPLETED_ACTION = "INITIATE"; + + public static final String URI_TENANT_ID_PARAM = "tenantId"; + + public static final String URI_BUSINESS_SERVICE_PARAM = "businessService"; + + public static final String URI_BUSINESS_SERVICE_QUERY_TEMPLATE = "?tenantId={tenantId}&businessServices={businessService}"; + + public static final String APPROVE_CENSUS_DATA_ACTION = "APPROVE_CENSUS_DATA"; + + public static final String FINALIZE_CATCHMENT_MAPPING_ACTION = "FINALIZE_CATCHMENT_MAPPING"; + + public static final String APPROVE_ESTIMATIONS_ACTION = "APPROVE_ESTIMATIONS"; + + public static final String VALIDATED_STATUS = "VALIDATED"; + + //Query constants + public static final String PERCENTAGE_WILDCARD = "%"; + + public static final String MDMS_MASTER_HIERARCHY= "hierarchy"; + + public static final String ERROR_WHILE_FETCHING_FROM_FACILITY = "Exception occurred while fetching facility details from facility service "; + + public static final String ERROR_WHILE_FETCHING_BUSINESS_SERVICE_DETAILS = "Exception occurred while fetching business service details: "; + + public static final String INVALID_PLAN_FACILITY_ID_CODE = "INVALID_PLAN_FACILITY_ID"; + public static final String INVALID_PLAN_FACILITY_ID_MESSAGE = "Plan facility id provided is invalid"; + + public static final String INVALID_SERVICE_BOUNDARY_CODE = "INVALID_SERVICE_BOUNDARY"; + public static final String INVALID_SERVICE_BOUNDARY_MESSAGE = "The provided service boundary is invalid"; + + public static final String INVALID_RESIDING_BOUNDARY_CODE = "INVALID_RESIDING_BOUNDARY"; + public static final String INVALID_RESIDING_BOUNDARY_MESSAGE = "The provided residing boundary is invalid"; + + public static final String CANNOT_APPROVE_CENSUS_DATA_CODE = "CANNOT_APPROVE_CENSUS_DATA"; + public static final String CANNOT_APPROVE_CENSUS_DATA_MESSAGE = "Census data can't be approved until all the census records are validated"; + + public static final String CANNOT_APPROVE_ESTIMATIONS_CODE = "CANNOT_APPROVE_ESTIMATIONS"; + public static final String CANNOT_APPROVE_ESTIMATIONS_MESSAGE = "Estimations can't be approved until all the estimations are validated"; + + public static final String CANNOT_FINALIZE_CATCHMENT_MAPPING_CODE = "CANNOT_FINALIZE_CATCHMENT_MAPPING"; + public static final String CANNOT_FINALIZE_CATCHMENT_MAPPING_MESSAGE = "Catchment mapping can't be finalized until all boundaries have facility assigned"; + + public static final String HIERARCHY_NOT_FOUND_IN_MDMS_CODE = "HIERARCHY_NOT_FOUND_IN_MDMS"; + public static final String HIERARCHY_NOT_FOUND_IN_MDMS_MESSAGE = "Hierarchy key not found in mdms"; + + public static final String FAILED_MESSAGE = "Failed to push message to topic"; + + public static final String FACILITY_NAME_SEARCH_PARAMETER_KEY = "facilityName"; + + public static final String FACILITY_STATUS_SEARCH_PARAMETER_KEY = "facilityStatus"; + + public static final String FACILITY_TYPE_SEARCH_PARAMETER_KEY = "facilityType"; + + public static final String COMMA_DELIMITER = ","; + + public static final String SERVING_POPULATION_CODE = "servingPopulation"; + + public static final String CONFIRMED_TARGET_POPULATION_AGE_3TO11 = "CONFIRMED_HCM_ADMIN_CONSOLE_TARGET_POPULATION_AGE_3TO11"; + + public static final String CONFIRMED_TARGET_POPULATION_AGE_12TO59 = "CONFIRMED_HCM_ADMIN_CONSOLE_TARGET_POPULATION_AGE_12TO59"; + + public static final String CONFIRMED_TARGET_POPULATION = "CONFIRMED_HCM_ADMIN_CONSOLE_TARGET_POPULATION"; + } diff --git a/health-services/plan-service/src/main/java/digit/kafka/ProjectFactoryCreatePlanFacilityConsumer.java b/health-services/plan-service/src/main/java/digit/kafka/ProjectFactoryCreatePlanFacilityConsumer.java new file mode 100644 index 00000000000..f01da2db239 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/kafka/ProjectFactoryCreatePlanFacilityConsumer.java @@ -0,0 +1,57 @@ +package digit.kafka; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.repository.PlanFacilityRepository; +import digit.service.enrichment.PlanFacilityEnricher; +import digit.util.CommonUtil; +import digit.web.models.PlanFacilityRequest; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Map; + +import static digit.config.ServiceConstants.HIERARCHY_TYPE; + +@Slf4j +@Component +public class ProjectFactoryCreatePlanFacilityConsumer { + + private ObjectMapper objectMapper; + + private PlanFacilityEnricher enrichment; + + private CommonUtil commonUtil; + + private PlanFacilityRepository repository; + + public ProjectFactoryCreatePlanFacilityConsumer(ObjectMapper objectMapper, PlanFacilityEnricher enrichment, CommonUtil commonUtil, PlanFacilityRepository repository) { + this.objectMapper = objectMapper; + this.enrichment = enrichment; + this.commonUtil = commonUtil; + this.repository = repository; + } + + @KafkaListener(topics = {"${project.factory.save.plan.facility.consumer.topic}"}) + public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + PlanFacilityRequest planFacilityRequest = objectMapper.convertValue(consumerRecord, PlanFacilityRequest.class); + String hierarchyType = commonUtil.extractFieldsFromJsonObject(planFacilityRequest.getPlanFacility().getAdditionalDetails(), HIERARCHY_TYPE).toString(); + + if(!StringUtils.isEmpty(hierarchyType)) + enrichment.enrichJurisdictionMapping(planFacilityRequest, hierarchyType); + + if(CollectionUtils.isEmpty(planFacilityRequest.getPlanFacility().getServiceBoundaries())) + planFacilityRequest.getPlanFacility().setServiceBoundaries(new ArrayList<>()); + + repository.create(planFacilityRequest); + } catch (Exception exception) { + log.error("Error in census consumer", exception); + } + } +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/kafka/UpdatePlanConfigConsumer.java b/health-services/plan-service/src/main/java/digit/kafka/UpdatePlanConfigConsumer.java index ca72bb21058..b2a97f1d77d 100644 --- a/health-services/plan-service/src/main/java/digit/kafka/UpdatePlanConfigConsumer.java +++ b/health-services/plan-service/src/main/java/digit/kafka/UpdatePlanConfigConsumer.java @@ -28,6 +28,7 @@ public UpdatePlanConfigConsumer(PlanConfigurationService planConfigurationServic public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { PlanConfigurationRequest planConfigurationRequest = objectMapper.convertValue(consumerRecord, PlanConfigurationRequest.class); + log.info("Update plan config from resource generator."); planConfigurationService.update(planConfigurationRequest); } catch (Exception exception) { log.error("Error in update plan configuration consumer while processing topic {}: {}", topic, consumerRecord, exception); diff --git a/health-services/plan-service/src/main/java/digit/repository/PlanConfigurationRepository.java b/health-services/plan-service/src/main/java/digit/repository/PlanConfigurationRepository.java index 49efc1d89f4..62af2daaac4 100644 --- a/health-services/plan-service/src/main/java/digit/repository/PlanConfigurationRepository.java +++ b/health-services/plan-service/src/main/java/digit/repository/PlanConfigurationRepository.java @@ -16,5 +16,6 @@ public interface PlanConfigurationRepository { public void update(PlanConfigurationRequest planConfigurationRequest); + public Integer count(PlanConfigurationSearchCriteria planConfigurationSearchCriteria); } diff --git a/health-services/plan-service/src/main/java/digit/repository/PlanEmployeeAssignmentRepository.java b/health-services/plan-service/src/main/java/digit/repository/PlanEmployeeAssignmentRepository.java new file mode 100644 index 00000000000..370141a8697 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/PlanEmployeeAssignmentRepository.java @@ -0,0 +1,16 @@ +package digit.repository; + +import digit.web.models.*; + +import java.util.List; + +public interface PlanEmployeeAssignmentRepository { + + public void create(PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest); + + public List search(PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria); + + public void update(PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest); + + public Integer count(PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria); +} diff --git a/health-services/plan-service/src/main/java/digit/repository/PlanFacilityRepository.java b/health-services/plan-service/src/main/java/digit/repository/PlanFacilityRepository.java new file mode 100644 index 00000000000..ce94f569086 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/PlanFacilityRepository.java @@ -0,0 +1,15 @@ +package digit.repository; + +import digit.web.models.*; + +import java.util.List; + +public interface PlanFacilityRepository { + public void create(PlanFacilityRequest planFacilityRequest); + + public List search(PlanFacilitySearchCriteria planFacilitySearchCriteria); + + void update(PlanFacilityRequest planFacilityRequest); + + public Integer count(PlanFacilitySearchCriteria planFacilitySearchCriteria); +} diff --git a/health-services/plan-service/src/main/java/digit/repository/PlanRepository.java b/health-services/plan-service/src/main/java/digit/repository/PlanRepository.java index eb76b357701..1b8c334ed7c 100644 --- a/health-services/plan-service/src/main/java/digit/repository/PlanRepository.java +++ b/health-services/plan-service/src/main/java/digit/repository/PlanRepository.java @@ -1,10 +1,9 @@ package digit.repository; -import digit.web.models.Plan; -import digit.web.models.PlanRequest; -import digit.web.models.PlanSearchCriteria; +import digit.web.models.*; import java.util.List; +import java.util.Map; public interface PlanRepository { public void create(PlanRequest planRequest); @@ -13,4 +12,9 @@ public interface PlanRepository { public void update(PlanRequest planRequest); + public Integer count(PlanSearchCriteria planSearchCriteria); + + public Map statusCount(PlanSearchRequest planSearchRequest); + + public void bulkUpdate(BulkPlanRequest body); } diff --git a/health-services/plan-service/src/main/java/digit/repository/ServiceRequestRepository.java b/health-services/plan-service/src/main/java/digit/repository/ServiceRequestRepository.java index d09d230e4fa..5a724b5b219 100644 --- a/health-services/plan-service/src/main/java/digit/repository/ServiceRequestRepository.java +++ b/health-services/plan-service/src/main/java/digit/repository/ServiceRequestRepository.java @@ -4,8 +4,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ServiceCallException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; @@ -35,9 +35,10 @@ public Object fetchResult(StringBuilder uri, Object request) { response = restTemplate.postForObject(uri.toString(), request, Map.class); } catch (HttpClientErrorException e) { log.error(EXTERNAL_SERVICE_EXCEPTION, e); - throw new ServiceCallException(e.getResponseBodyAsString()); + throw new CustomException(EXTERNAL_SERVICE_EXCEPTION, e.getResponseBodyAsString()); } catch (Exception e) { log.error(SEARCHER_SERVICE_EXCEPTION, e); + throw new CustomException(EXTERNAL_SERVICE_EXCEPTION, e.getMessage()); } return response; diff --git a/health-services/plan-service/src/main/java/digit/repository/impl/PlanEmployeeAssignmentImpl.java b/health-services/plan-service/src/main/java/digit/repository/impl/PlanEmployeeAssignmentImpl.java new file mode 100644 index 00000000000..bba32818812 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/impl/PlanEmployeeAssignmentImpl.java @@ -0,0 +1,121 @@ +package digit.repository.impl; + +import digit.config.Configuration; +import digit.kafka.Producer; +import digit.repository.PlanEmployeeAssignmentRepository; +import digit.repository.querybuilder.PlanEmployeeAssignmentQueryBuilder; +import digit.repository.rowmapper.PlanEmployeeAssignmentRowMapper; +import digit.web.models.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Repository +public class PlanEmployeeAssignmentImpl implements PlanEmployeeAssignmentRepository { + + private Producer producer; + + private Configuration config; + + private PlanEmployeeAssignmentQueryBuilder queryBuilder; + + private JdbcTemplate jdbcTemplate; + + private PlanEmployeeAssignmentRowMapper rowMapper; + + public PlanEmployeeAssignmentImpl(Producer producer, Configuration config, PlanEmployeeAssignmentQueryBuilder queryBuilder, JdbcTemplate jdbcTemplate, PlanEmployeeAssignmentRowMapper rowMapper) { + this.producer = producer; + this.config = config; + this.queryBuilder = queryBuilder; + this.jdbcTemplate = jdbcTemplate; + this.rowMapper = rowMapper; + } + + /** + * Pushes a new plan employee assignment to persister kafka topic. + * + * @param planEmployeeAssignmentRequest The request containing the plan employee assignment details. + */ + @Override + public void create(PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest) { + PlanEmployeeAssignmentRequestDTO requestDTO = convertToReqDTO(planEmployeeAssignmentRequest); + producer.push(config.getPlanEmployeeAssignmentCreateTopic(), requestDTO); + } + + /** + * Searches for Plan employee assignments based on provided search criteria + * + * @param searchCriteria The criteria used for searching plan employee assignments + * @return A list of Plan employee assignments that matches the search criteria + */ + @Override + public List search(PlanEmployeeAssignmentSearchCriteria searchCriteria) { + List preparedStmtList = new ArrayList<>(); + String searchQuery = queryBuilder.getPlanEmployeeAssignmentQuery(searchCriteria, preparedStmtList); + log.info("Plan Employee Assignment search query : " + searchQuery); + + List planEmployeeAssignments = jdbcTemplate.query(searchQuery, rowMapper, preparedStmtList.toArray()); + return planEmployeeAssignments; + } + + /** + * Counts the number of plan employee assignments based on the provided search criteria. + * + * @param searchCriteria The search criteria for filtering plan employee assignments. + * @return The total count of plan employee assignment matching the search criteria. + */ + @Override + public Integer count(PlanEmployeeAssignmentSearchCriteria searchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getPlanEmployeeAssignmentCountQuery(searchCriteria, preparedStmtList); + Integer count = jdbcTemplate.queryForObject(query, preparedStmtList.toArray(), Integer.class); + + return count; + } + + /** + * Pushes an updated existing plan employee assignment to persister kafka topic. + * + * @param planEmployeeAssignmentRequest The request containing the updated plan employee assignment details. + */ + @Override + public void update(PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest) { + PlanEmployeeAssignmentRequestDTO requestDTO = convertToReqDTO(planEmployeeAssignmentRequest); + producer.push(config.getPlanEmployeeAssignmentUpdateTopic(), requestDTO); + } + + /** + * Converts the PlanEmployeeAssignmentRequest to a data transfer object (DTO) + * + * @param planEmployeeAssignmentRequest The request to be converted to DTO + * @return a DTO for PlanEmployeeAssignmentRequest + */ + public PlanEmployeeAssignmentRequestDTO convertToReqDTO(PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest) { + PlanEmployeeAssignment planEmployeeAssignment = planEmployeeAssignmentRequest.getPlanEmployeeAssignment(); + + // Creating a new data transfer object (DTO) for PlanEmployeeAssignment + PlanEmployeeAssignmentDTO planEmployeeAssignmentDTO = PlanEmployeeAssignmentDTO.builder() + .id(planEmployeeAssignment.getId()) + .tenantId(planEmployeeAssignment.getTenantId()) + .planConfigurationId(planEmployeeAssignment.getPlanConfigurationId()) + .employeeId(planEmployeeAssignment.getEmployeeId()) + .role(planEmployeeAssignment.getRole()) + .planConfigurationName(planEmployeeAssignment.getPlanConfigurationName()) + .hierarchyLevel(planEmployeeAssignment.getHierarchyLevel()) + .jurisdiction(String.join(",", planEmployeeAssignment.getJurisdiction())) + .additionalDetails(planEmployeeAssignment.getAdditionalDetails()) + .active(planEmployeeAssignment.getActive()) + .auditDetails(planEmployeeAssignment.getAuditDetails()) + .build(); + + return PlanEmployeeAssignmentRequestDTO.builder() + .requestInfo(planEmployeeAssignmentRequest.getRequestInfo()) + .planEmployeeAssignmentDTO(planEmployeeAssignmentDTO) + .build(); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/repository/impl/PlanFacilityRepositoryImpl.java b/health-services/plan-service/src/main/java/digit/repository/impl/PlanFacilityRepositoryImpl.java new file mode 100644 index 00000000000..2d3c2304bae --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/impl/PlanFacilityRepositoryImpl.java @@ -0,0 +1,150 @@ +package digit.repository.impl; + +import digit.config.Configuration; +import digit.kafka.Producer; +import digit.repository.PlanFacilityRepository; +import digit.repository.querybuilder.PlanFacilityQueryBuilder; +import digit.repository.rowmapper.PlanFacilityRowMapper; +import digit.web.models.*; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.CustomException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import java.util.ArrayList; +import java.util.List; +import static digit.config.ServiceConstants.*; + +@Repository +@Slf4j +public class PlanFacilityRepositoryImpl implements PlanFacilityRepository { + + private Producer producer; + + private JdbcTemplate jdbcTemplate; + + private PlanFacilityQueryBuilder planFacilityQueryBuilder; + + private PlanFacilityRowMapper planFacilityRowMapper; + + private Configuration config; + + public PlanFacilityRepositoryImpl(Producer producer, JdbcTemplate jdbcTemplate, PlanFacilityQueryBuilder planFacilityQueryBuilder, PlanFacilityRowMapper planFacilityRowMapper, Configuration config) { + this.producer = producer; + this.jdbcTemplate = jdbcTemplate; + this.planFacilityQueryBuilder = planFacilityQueryBuilder; + this.planFacilityRowMapper = planFacilityRowMapper; + this.config = config; + } + + /** + * This method emits an event to the persister for it to save the plan facility linkage in the database. + * @param planFacilityRequest + */ + @Override + public void create(PlanFacilityRequest planFacilityRequest) { + // Convert the incoming PlanFacilityRequest to PlanFacilityRequestDTO + PlanFacilityRequestDTO requestDTO = convertToDTO(planFacilityRequest); + + // Push the requestDTO to the producer for processing + producer.push(config.getPlanFacilityCreateTopic(), requestDTO); + } + + public PlanFacilityRequestDTO convertToDTO(PlanFacilityRequest planFacilityRequest) { + PlanFacility planFacility = planFacilityRequest.getPlanFacility(); + + // Create a new PlanFacilityDTO + PlanFacilityDTO planFacilityDTO = PlanFacilityDTO.builder() + .id(planFacility.getId()) + .tenantId(planFacility.getTenantId()) + .planConfigurationId(planFacility.getPlanConfigurationId()) + .planConfigurationName(planFacility.getPlanConfigurationName()) + .facilityId(planFacility.getFacilityId()) + .facilityName(planFacility.getFacilityName()) + .jurisdictionMapping(planFacility.getJurisdictionMapping()) + .boundaryAncestralPath(planFacility.getBoundaryAncestralPath()) + .residingBoundary(planFacility.getResidingBoundary()) + .serviceBoundaries(convertArrayToString(planFacility.getServiceBoundaries())) + .initiallySetServiceBoundaries(planFacility.getInitiallySetServiceBoundaries()) + .additionalDetails(planFacility.getAdditionalDetails()) + .active(planFacility.getActive()) + .auditDetails(planFacility.getAuditDetails()) + .build(); + + // Return the complete PlanFacilityRequestDTO + return PlanFacilityRequestDTO.builder() + .requestInfo(planFacilityRequest.getRequestInfo()) + .planFacilityDTO(planFacilityDTO) + .build(); + } + + /** + * This is a helper function to convert an array of string to comma separated string + * + * @param stringList Array of string to be converted + * @return a string + */ + private String convertArrayToString(List stringList) { + return String.join(COMMA_DELIMITER, stringList); + } + + + + /** + * This method searches for plans based on the search criteria. + * + * @param planFacilitySearchCriteria + * @return List + */ + @Override + public List search(PlanFacilitySearchCriteria planFacilitySearchCriteria) { + // Fetch plan facility from database + return queryDatabaseForPlanFacilities(planFacilitySearchCriteria); + } + + /** + * This method emits an event to the persister for it to update the plan facility in the database. + * + * @param planFacilityRequest + */ + @Override + public void update(PlanFacilityRequest planFacilityRequest) { + try { + PlanFacilityRequestDTO requestDTO = convertToDTO(planFacilityRequest); + producer.push(config.getPlanFacilityUpdateTopic(), requestDTO); + log.info("Successfully pushed update for plan facility: {}", planFacilityRequest.getPlanFacility().getId()); + } catch (Exception e) { + throw new CustomException(FAILED_MESSAGE,config.getPlanFacilityUpdateTopic()); + } + } + + /** + * Counts the number of plan facilities based on the provided search criteria. + * + * @param planFacilitySearchCriteria The search criteria for filtering plan facilities. + * @return The total count of plan facilities matching the search criteria. + */ + @Override + public Integer count(PlanFacilitySearchCriteria planFacilitySearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = planFacilityQueryBuilder.getPlanFacilityCountQuery(planFacilitySearchCriteria, preparedStmtList); + Integer count = jdbcTemplate.queryForObject(query, preparedStmtList.toArray(), Integer.class); + + return count; + } + + /** + * Helper method to query database for plan facilities based on the provided search criteria. + * + * @param planFacilitySearchCriteria + * @return List + */ + private List queryDatabaseForPlanFacilities(PlanFacilitySearchCriteria planFacilitySearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = planFacilityQueryBuilder.getPlanFacilitySearchQuery(planFacilitySearchCriteria, preparedStmtList); + log.info("Plan facility search {}", query); + log.info(preparedStmtList.toString()); + return jdbcTemplate.query(query, planFacilityRowMapper, preparedStmtList.toArray()); + } + + +} diff --git a/health-services/plan-service/src/main/java/digit/repository/impl/PlanRepositoryImpl.java b/health-services/plan-service/src/main/java/digit/repository/impl/PlanRepositoryImpl.java index c6acbb55221..99e4b9487de 100644 --- a/health-services/plan-service/src/main/java/digit/repository/impl/PlanRepositoryImpl.java +++ b/health-services/plan-service/src/main/java/digit/repository/impl/PlanRepositoryImpl.java @@ -5,17 +5,21 @@ import digit.repository.PlanRepository; import digit.repository.querybuilder.PlanQueryBuilder; import digit.repository.rowmapper.PlanRowMapper; -import digit.web.models.Plan; -import digit.web.models.PlanRequest; -import digit.web.models.PlanSearchCriteria; +import digit.repository.rowmapper.PlanStatusCountRowMapper; +import digit.service.workflow.WorkflowService; +import digit.web.models.*; import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.SingleColumnRowMapper; import org.springframework.stereotype.Repository; import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; import java.util.ArrayList; import java.util.List; +import java.util.Map; + +import static digit.config.ServiceConstants.PLAN_ESTIMATION_BUSINESS_SERVICE; @Slf4j @Repository @@ -31,13 +35,19 @@ public class PlanRepositoryImpl implements PlanRepository { private Configuration config; + private PlanStatusCountRowMapper statusCountRowMapper; + + private WorkflowService workflowService; + public PlanRepositoryImpl(Producer producer, PlanQueryBuilder planQueryBuilder, PlanRowMapper planRowMapper, - JdbcTemplate jdbcTemplate, Configuration config) { + JdbcTemplate jdbcTemplate, Configuration config, PlanStatusCountRowMapper statusCountRowMapper, WorkflowService workflowService) { this.producer = producer; this.planQueryBuilder = planQueryBuilder; this.planRowMapper = planRowMapper; this.jdbcTemplate = jdbcTemplate; this.config = config; + this.statusCountRowMapper = statusCountRowMapper; + this.workflowService = workflowService; } /** @@ -46,11 +56,8 @@ public PlanRepositoryImpl(Producer producer, PlanQueryBuilder planQueryBuilder, */ @Override public void create(PlanRequest planRequest) { - try { - producer.push(config.getPlanCreateTopic(), planRequest); - } catch (Exception e) { - log.info("Pushing message to topic " + config.getPlanCreateTopic() + " failed.", e); - } + PlanRequestDTO planRequestDTO = convertToPlanReqDTO(planRequest); + producer.push(config.getPlanCreateTopic(), planRequestDTO); } /** @@ -70,9 +77,29 @@ public List search(PlanSearchCriteria planSearchCriteria) { } // Fetch plans from database based on the acquired ids - List plans = searchPlanByIds(planIds); + return searchPlanByIds(planIds); + } - return plans; + /** + * Counts the plan based on their current status for the provided search criteria. + * + * @param planSearchRequest The search criteria for filtering plans. + * @return The status count of plans for the given search criteria. + */ + @Override + public Map statusCount(PlanSearchRequest planSearchRequest) { + List preparedStmtList = new ArrayList<>(); + List statusList = workflowService.getStatusFromBusinessService(planSearchRequest.getRequestInfo(), PLAN_ESTIMATION_BUSINESS_SERVICE, planSearchRequest.getPlanSearchCriteria().getTenantId()); + + String query = planQueryBuilder.getPlanStatusCountQuery(planSearchRequest.getPlanSearchCriteria(), preparedStmtList); + Map statusCountMap = jdbcTemplate.query(query, statusCountRowMapper, preparedStmtList.toArray()); + + statusList.forEach(status -> { + if(ObjectUtils.isEmpty(statusCountMap.get(status))) + statusCountMap.put(status, 0); + }); + + return statusCountMap; } /** @@ -81,13 +108,41 @@ public List search(PlanSearchCriteria planSearchCriteria) { */ @Override public void update(PlanRequest planRequest) { - try { - producer.push(config.getPlanUpdateTopic(), planRequest); - } catch (Exception e) { - log.info("Pushing message to topic " + config.getPlanUpdateTopic() + " failed.", e); - } + PlanRequestDTO planRequestDTO = convertToPlanReqDTO(planRequest); + producer.push(config.getPlanUpdateTopic(), planRequestDTO); } + @Override + public void bulkUpdate(BulkPlanRequest body) { + // Get bulk plan update query + String bulkPlanUpdateQuery = planQueryBuilder.getBulkPlanQuery(); + + // Prepare rows for bulk update + List rows = body.getPlans().stream().map(plan -> new Object[] { + plan.getStatus(), + !CollectionUtils.isEmpty(plan.getAssignee()) ? String.join(",", plan.getAssignee()) : plan.getAssignee(), + plan.getAuditDetails().getLastModifiedBy(), + plan.getAuditDetails().getLastModifiedTime(), + plan.getId() + }).toList(); + + // Perform batch update + jdbcTemplate.batchUpdate(bulkPlanUpdateQuery, rows); + producer.push(config.getPlanBulkUpdateTopic(), body); + } + + /** + * Counts the number of plans based on the provided search criteria. + * @param planSearchCriteria The search criteria for filtering plans. + * @return The total count of plans matching the search criteria. + */ + @Override + public Integer count(PlanSearchCriteria planSearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = planQueryBuilder.getPlanCountQuery(planSearchCriteria, preparedStmtList); + return jdbcTemplate.queryForObject(query, preparedStmtList.toArray(), Integer.class); + } + /** * Helper method to query database for plan ids based on the provided search criteria. * @param planSearchCriteria @@ -112,4 +167,41 @@ private List searchPlanByIds(List planIds) { return jdbcTemplate.query(query, planRowMapper, preparedStmtList.toArray()); } + /** + * Converts the PlanRequest to a data transfer object (DTO) + * + * @param planRequest The request to be converted to DTO + * @return a DTO for PlanRequest + */ + private PlanRequestDTO convertToPlanReqDTO(PlanRequest planRequest) { + Plan plan = planRequest.getPlan(); + + String assignee = !CollectionUtils.isEmpty(plan.getAssignee()) ? String.join(",", plan.getAssignee()) : null; + + // Creating a new data transfer object (DTO) for Plan + PlanDTO planDTO = PlanDTO.builder() + .id(plan.getId()) + .tenantId(plan.getTenantId()) + .locality(plan.getLocality()) + .campaignId(plan.getCampaignId()) + .planConfigurationId(plan.getPlanConfigurationId()) + .status(plan.getStatus()) + .assignee(assignee) + .additionalDetails(plan.getAdditionalDetails()) + .jurisdictionMapping(plan.getJurisdictionMapping()) + .activities(plan.getActivities()) + .resources(plan.getResources()) + .targets(plan.getTargets()) + .auditDetails(plan.getAuditDetails()) + .boundaryAncestralPath(plan.getBoundaryAncestralPath()) + .build(); + + // Returning the PlanRequestDTO + return PlanRequestDTO.builder() + .requestInfo(planRequest.getRequestInfo()) + .planDTO(planDTO) + .build(); + } + + } diff --git a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanConfigQueryBuilder.java b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanConfigQueryBuilder.java index 6dc4449b55f..e8caef51d94 100644 --- a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanConfigQueryBuilder.java +++ b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanConfigQueryBuilder.java @@ -1,30 +1,35 @@ package digit.repository.querybuilder; import digit.config.Configuration; - import digit.util.QueryUtil; import digit.web.models.PlanConfigurationSearchCriteria; -import java.util.LinkedHashSet; -import java.util.List; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; +import java.util.LinkedHashSet; +import java.util.List; + +import static digit.config.ServiceConstants.PERCENTAGE_WILDCARD; + @Component public class PlanConfigQueryBuilder { private Configuration config; - public PlanConfigQueryBuilder(Configuration config) { + private QueryUtil queryUtil; + + public PlanConfigQueryBuilder(Configuration config, QueryUtil queryUtil) { this.config = config; + this.queryUtil = queryUtil; } private static final String PLAN_CONFIG_SEARCH_BASE_QUERY = "SELECT id FROM plan_configuration pc "; - private static final String PLAN_CONFIG_QUERY = "SELECT pc.id as plan_configuration_id, pc.tenant_id as plan_configuration_tenant_id, pc.name as plan_configuration_name, pc.execution_plan_id as plan_configuration_execution_plan_id, pc.status as plan_configuration_status, pc.created_by as plan_configuration_created_by, pc.created_time as plan_configuration_created_time, pc.last_modified_by as plan_configuration_last_modified_by, pc.last_modified_time as plan_configuration_last_modified_time, \n" + + private static final String PLAN_CONFIG_QUERY = "SELECT pc.id as plan_configuration_id, pc.tenant_id as plan_configuration_tenant_id, pc.name as plan_configuration_name, pc.campaign_id as plan_configuration_campaign_id, pc.status as plan_configuration_status, pc.additional_details as plan_configuration_additional_details, pc.created_by as plan_configuration_created_by, pc.created_time as plan_configuration_created_time, pc.last_modified_by as plan_configuration_last_modified_by, pc.last_modified_time as plan_configuration_last_modified_time, \n" + "\t pcf.id as plan_configuration_files_id, pcf.plan_configuration_id as plan_configuration_files_plan_configuration_id, pcf.filestore_id as plan_configuration_files_filestore_id, pcf.input_file_type as plan_configuration_files_input_file_type, pcf.template_identifier as plan_configuration_files_template_identifier, pcf.active as plan_configuration_files_active, pcf.created_by as plan_configuration_files_created_by, pcf.created_time as plan_configuration_files_created_time, pcf.last_modified_by as plan_configuration_files_last_modified_by, pcf.last_modified_time as plan_configuration_files_last_modified_time,\n" + - "\t pca.id as plan_configuration_assumptions_id, pca.key as plan_configuration_assumptions_key, pca.value as plan_configuration_assumptions_value, pca.active as plan_configuration_assumptions_active, pca.plan_configuration_id as plan_configuration_assumptions_plan_configuration_id, pca.created_by as plan_configuration_assumptions_created_by, pca.created_time as plan_configuration_assumptions_created_time, pca.last_modified_by as plan_configuration_assumptions_last_modified_by, pca.last_modified_time as plan_configuration_assumptions_last_modified_time,\n" + - "\t pco.id as plan_configuration_operations_id, pco.input as plan_configuration_operations_input, pco.operator as plan_configuration_operations_operator, pco.assumption_value as plan_configuration_operations_assumption_value, pco.output as plan_configuration_operations_output, pco.active as plan_configuration_operations_active, pco.plan_configuration_id as plan_configuration_operations_plan_configuration_id, pco.created_by as plan_configuration_operations_created_by, pco.created_time as plan_configuration_operations_created_time, pco.last_modified_by as plan_configuration_operations_last_modified_by, pco.last_modified_time as plan_configuration_operations_last_modified_time,\n" + + "\t pca.id as plan_configuration_assumptions_id, pca.key as plan_configuration_assumptions_key, pca.value as plan_configuration_assumptions_value, pca.source as plan_configuration_assumptions_source, pca.category as plan_configuration_assumptions_category, pca.active as plan_configuration_assumptions_active, pca.plan_configuration_id as plan_configuration_assumptions_plan_configuration_id, pca.created_by as plan_configuration_assumptions_created_by, pca.created_time as plan_configuration_assumptions_created_time, pca.last_modified_by as plan_configuration_assumptions_last_modified_by, pca.last_modified_time as plan_configuration_assumptions_last_modified_time,\n" + + "\t pco.id as plan_configuration_operations_id, pco.input as plan_configuration_operations_input, pco.operator as plan_configuration_operations_operator, pco.assumption_value as plan_configuration_operations_assumption_value, pco.output as plan_configuration_operations_output, pco.source as plan_configuration_operations_source, pco.category as plan_configuration_operations_category, pco.active as plan_configuration_operations_active, pco.execution_order as plan_configuration_execution_order, pco.show_on_estimation_dashboard as plan_configuration_operations_show_on_estimation_dashboard,pco.plan_configuration_id as plan_configuration_operations_plan_configuration_id, pco.created_by as plan_configuration_operations_created_by, pco.created_time as plan_configuration_operations_created_time, pco.last_modified_by as plan_configuration_operations_last_modified_by, pco.last_modified_time as plan_configuration_operations_last_modified_time,\n" + "\t pcm.id as plan_configuration_mapping_id, pcm.filestore_id as plan_configuration_mapping_filestore_id, pcm.mapped_from as plan_configuration_mapping_mapped_from, pcm.mapped_to as plan_configuration_mapping_mapped_to, pcm.active as plan_configuration_mapping_active, pcm.plan_configuration_id as plan_configuration_mapping_plan_configuration_id, pcm.created_by as plan_configuration_mapping_created_by, pcm.created_time as plan_configuration_mapping_created_time, pcm.last_modified_by as plan_configuration_mapping_last_modified_by, pcm.last_modified_time as plan_configuration_mapping_last_modified_time\n" + "\t FROM plan_configuration pc\n" + "\t LEFT JOIN plan_configuration_files pcf ON pc.id = pcf.plan_configuration_id\n" + @@ -44,14 +49,14 @@ private String buildPlanConfigQuery(List ids, List preparedStmtL StringBuilder builder = new StringBuilder(PLAN_CONFIG_QUERY); if (!CollectionUtils.isEmpty(ids)) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); - builder.append(" pc.id IN ( ").append(QueryUtil.createQuery(ids.size())).append(" )"); - QueryUtil.addToPreparedStatement(preparedStmtList, new LinkedHashSet<>(ids)); + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pc.id IN ( ").append(queryUtil.createQuery(ids.size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, ids); } addActiveWhereClause(builder, preparedStmtList); - return QueryUtil.addOrderByClause(builder.toString(), PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE); + return queryUtil.addOrderByClause(builder.toString(), PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE); } /** @@ -64,7 +69,7 @@ private String buildPlanConfigQuery(List ids, List preparedStmtL */ public String getPlanConfigSearchQuery(PlanConfigurationSearchCriteria criteria, List preparedStmtList) { String query = buildPlanConfigSearchQuery(criteria, preparedStmtList, Boolean.FALSE); - query = QueryUtil.addOrderByClause(query, PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE); + query = queryUtil.addOrderByClause(query, PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE); query = getPaginatedQuery(query, criteria, preparedStmtList); return query; @@ -97,22 +102,28 @@ private String buildPlanConfigSearchQuery(PlanConfigurationSearchCriteria criter preparedStmtList.add(criteria.getId()); } - if (criteria.getExecutionPlanId() != null) { + if (!CollectionUtils.isEmpty(criteria.getIds())) { + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pc.id IN ( ").append(queryUtil.createQuery(criteria.getIds().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, criteria.getIds()); + } + + if (criteria.getCampaignId() != null) { addClauseIfRequired(preparedStmtList, builder); - builder.append(" pc.execution_plan_id = ?"); - preparedStmtList.add(criteria.getExecutionPlanId()); + builder.append(" pc.campaign_id = ?"); + preparedStmtList.add(criteria.getCampaignId()); } if (criteria.getName() != null) { addClauseIfRequired(preparedStmtList, builder); - builder.append(" pc.name = ?"); - preparedStmtList.add(criteria.getName()); + builder.append(" pc.name ILIKE ?"); + preparedStmtList.add(PERCENTAGE_WILDCARD + criteria.getName() + PERCENTAGE_WILDCARD); } - if (criteria.getStatus() != null) { + if (!CollectionUtils.isEmpty(criteria.getStatus())) { addClauseIfRequired(preparedStmtList, builder); - builder.append(" pc.status = ?"); - preparedStmtList.add(criteria.getStatus()); + builder.append(" pc.status IN ( ").append(queryUtil.createQuery(criteria.getStatus().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, criteria.getStatus()); } if (criteria.getUserUuid() != null) { @@ -162,22 +173,21 @@ private String getPaginatedQuery(String query, PlanConfigurationSearchCriteria p return paginatedQuery.toString(); } - public void addActiveWhereClause(StringBuilder builder, List preparedStmtList) - { + public void addActiveWhereClause(StringBuilder builder, List preparedStmtList) { addClauseIfRequired(preparedStmtList, builder); - builder.append(" pcf.active = ?"); + builder.append(" ( pcf.active = ? OR pcf.active IS NULL )"); preparedStmtList.add(Boolean.TRUE); addClauseIfRequired(preparedStmtList, builder); - builder.append(" pca.active = ?"); + builder.append(" ( pca.active = ? OR pca.active IS NULL )"); preparedStmtList.add(Boolean.TRUE); addClauseIfRequired(preparedStmtList, builder); - builder.append(" pco.active = ?"); + builder.append(" ( pco.active = ? OR pco.active IS NULL )"); preparedStmtList.add(Boolean.TRUE); addClauseIfRequired(preparedStmtList, builder); - builder.append(" pcm.active = ?"); + builder.append(" ( pcm.active = ? OR pcm.active IS NULL )"); preparedStmtList.add(Boolean.TRUE); } diff --git a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanEmployeeAssignmentQueryBuilder.java b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanEmployeeAssignmentQueryBuilder.java new file mode 100644 index 00000000000..b63f790f806 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanEmployeeAssignmentQueryBuilder.java @@ -0,0 +1,170 @@ +package digit.repository.querybuilder; + +import digit.config.Configuration; +import digit.util.QueryUtil; +import digit.web.models.PlanEmployeeAssignmentSearchCriteria; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; + +import static digit.config.ServiceConstants.PERCENTAGE_WILDCARD; + +@Component +public class PlanEmployeeAssignmentQueryBuilder { + + private QueryUtil queryUtil; + + private Configuration config; + + public PlanEmployeeAssignmentQueryBuilder(QueryUtil queryUtil, Configuration config) { + + this.queryUtil = queryUtil; + this.config = config; + } + + private static final String PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_BASE_QUERY = "SELECT pa.id, pa.tenant_id, pa.plan_configuration_id, pa.plan_configuration_name, pa.employee_id, pa.role, pa.hierarchy_level, pa.jurisdiction, pa.additional_details, pa.active, pa.created_by, pa.created_time, pa.last_modified_by, pa.last_modified_time FROM plan_employee_assignment pa "; + + private static final String PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_ORDER_BY_CLAUSE = " ORDER BY pa.last_modified_time DESC"; + + private static final String UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_RANKED_QUERY = "WITH ranked_assignments AS ( SELECT pa.id, pa.tenant_id, pa.plan_configuration_id, pa.plan_configuration_name,pa.employee_id, pa.role, pa.hierarchy_level, pa.jurisdiction, pa.additional_details, pa.active, pa.created_by, pa.created_time, pa.last_modified_by, pa.last_modified_time, pc.last_modified_time AS pc_last_modified_time, ROW_NUMBER() OVER ( PARTITION BY pa.plan_configuration_id ORDER BY pc.last_modified_time DESC ) AS row_num FROM plan_employee_assignment pa JOIN plan_configuration pc ON pa.plan_configuration_id = pc.id "; + + private static final String UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_MAIN_SEARCH_QUERY = " SELECT id, tenant_id, plan_configuration_id, plan_configuration_name, employee_id, role, hierarchy_level, jurisdiction, additional_details, active, created_by, created_time, last_modified_by, last_modified_time FROM ranked_assignments WHERE row_num = 1 "; + + private static final String UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_ORDER_BY_CLAUSE = " ORDER BY pc_last_modified_time DESC "; + + private static final String PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_COUNT_WRAPPER = "SELECT COUNT(id) AS total_count FROM ( "; + + /** + * Constructs a SQL query string for searching PlanEmployeeAssignment objects based on the provided search criteria. + * Also adds an ORDER BY clause and handles pagination. + * + * @param searchCriteria The criteria used for filtering PlanEmployeeAssignment objects. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A complete SQL query string for searching PlanEmployeeAssignment objects. + */ + public String getPlanEmployeeAssignmentQuery(PlanEmployeeAssignmentSearchCriteria searchCriteria, List preparedStmtList) { + String query = buildPlanEmployeeAssignmentQuery(searchCriteria, preparedStmtList, Boolean.FALSE); + query = queryUtil.addOrderByClause(query, Boolean.TRUE.equals(searchCriteria.getFilterUniqueByPlanConfig()) ? + UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_ORDER_BY_CLAUSE : PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_ORDER_BY_CLAUSE); + query = getPaginatedQuery(query, searchCriteria, preparedStmtList); + return query; + } + + /** + * Constructs the count query to get the total count of plan employee assignments based on search criteria + * + * @param searchCriteria The criteria used for filtering PlanEmployeeAssignment objects. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A SQL query string to get the total count of plan employee assignments + */ + public String getPlanEmployeeAssignmentCountQuery(PlanEmployeeAssignmentSearchCriteria searchCriteria, List preparedStmtList) { + String query = buildPlanEmployeeAssignmentQuery(searchCriteria, preparedStmtList, Boolean.TRUE); + return query; + } + + /** + * Constructs query based on the provided search criteria + * + * @param searchCriteria The criteria used for filtering PlanEmployeeAssignment objects. + * @param preparedStmtList A list to store prepared statement parameters. + * @param isCount is true if count query is required for the provided search criteria + * @return A SQL query string for searching planEmployeeAssignment + */ + private String buildPlanEmployeeAssignmentQuery(PlanEmployeeAssignmentSearchCriteria searchCriteria, List preparedStmtList, Boolean isCount) { + StringBuilder builder = Boolean.TRUE.equals(searchCriteria.getFilterUniqueByPlanConfig()) ? + new StringBuilder(UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_RANKED_QUERY) : new StringBuilder(PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_BASE_QUERY); + + if (searchCriteria.getId() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.id = ?"); + preparedStmtList.add(searchCriteria.getId()); + } + + if (searchCriteria.getTenantId() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.tenant_id = ?"); + preparedStmtList.add(searchCriteria.getTenantId()); + } + + if (searchCriteria.getPlanConfigurationId() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.plan_configuration_id = ?"); + preparedStmtList.add(searchCriteria.getPlanConfigurationId()); + } + + if (searchCriteria.getPlanConfigurationName() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.plan_configuration_name ILIKE ?"); + preparedStmtList.add(PERCENTAGE_WILDCARD + searchCriteria.getPlanConfigurationName() + PERCENTAGE_WILDCARD); + } + + if (!CollectionUtils.isEmpty(searchCriteria.getEmployeeId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.employee_id IN ( ").append(queryUtil.createQuery(searchCriteria.getEmployeeId().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, searchCriteria.getEmployeeId()); + } + + if (!CollectionUtils.isEmpty(searchCriteria.getPlanConfigurationStatus())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pc.status IN ( ").append(queryUtil.createQuery(searchCriteria.getPlanConfigurationStatus().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, searchCriteria.getPlanConfigurationStatus()); + } + + if (!CollectionUtils.isEmpty(searchCriteria.getRole())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.role IN ( ").append(queryUtil.createQuery(searchCriteria.getRole().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, searchCriteria.getRole()); + } + + if(searchCriteria.getHierarchyLevel() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.hierarchy_level = ?"); + preparedStmtList.add(searchCriteria.getHierarchyLevel()); + } + + if (searchCriteria.getActive() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.active = ?"); + preparedStmtList.add(searchCriteria.getActive()); + } + + if (!CollectionUtils.isEmpty(searchCriteria.getJurisdiction())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ").append(queryUtil.createQuery(searchCriteria.getJurisdiction().size())).append(" ]").append("::text[] "); + builder.append(" && string_to_array(jurisdiction, ',') "); + queryUtil.addToPreparedStatement(preparedStmtList, searchCriteria.getJurisdiction()); + } + + if(searchCriteria.getFilterUniqueByPlanConfig()) { + builder.append(" )").append(UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_MAIN_SEARCH_QUERY); + } + + StringBuilder countQuery = new StringBuilder(); + if (isCount) { + countQuery.append(PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_COUNT_WRAPPER).append(builder); + countQuery.append(") AS subquery"); + + return countQuery.toString(); + } + + return builder.toString(); + } + + private String getPaginatedQuery(String query, PlanEmployeeAssignmentSearchCriteria searchCriteria, List preparedStmtList) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(ObjectUtils.isEmpty(searchCriteria.getOffset()) ? config.getDefaultOffset() : searchCriteria.getOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(ObjectUtils.isEmpty(searchCriteria.getLimit()) ? config.getDefaultLimit() : searchCriteria.getLimit()); + + return paginatedQuery.toString(); + } +} diff --git a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanFacilityQueryBuilder.java b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanFacilityQueryBuilder.java new file mode 100644 index 00000000000..0d475c4e577 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanFacilityQueryBuilder.java @@ -0,0 +1,154 @@ +package digit.repository.querybuilder; + +import digit.config.Configuration; +import digit.util.QueryUtil; +import digit.web.models.PlanFacilitySearchCriteria; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import static digit.config.ServiceConstants.PERCENTAGE_WILDCARD; + +@Component +public class PlanFacilityQueryBuilder { + + private Configuration config; + + private QueryUtil queryUtil; + + public PlanFacilityQueryBuilder(Configuration config, QueryUtil queryUtil) { + this.config = config; + this.queryUtil = queryUtil; + } + + private static final String PLAN_FACILITY_QUERY = + "SELECT plan_facility_linkage.id as plan_facility_id, " + + "plan_facility_linkage.tenant_id as plan_facility_tenant_id, " + + "plan_facility_linkage.plan_configuration_id as plan_facility_plan_configuration_id, " + + "plan_facility_linkage.plan_configuration_name as plan_facility_plan_configuration_name, " + + "plan_facility_linkage.facility_id as plan_facility_facility_id, " + + "plan_facility_linkage.facility_name as plan_facility_facility_name, " + + "plan_facility_linkage.boundary_ancestral_path as plan_facility_boundary_ancestral_path, " + + "plan_facility_linkage.residing_boundary as plan_facility_residing_boundary, " + + "plan_facility_linkage.service_boundaries as plan_facility_service_boundaries, " + + "plan_facility_linkage.additional_details as plan_facility_additional_details, " + + "plan_facility_linkage.created_by as plan_facility_created_by, " + + "plan_facility_linkage.created_time as plan_facility_created_time, " + + "plan_facility_linkage.last_modified_by as plan_facility_last_modified_by, " + + "plan_facility_linkage.last_modified_time as plan_facility_last_modified_time, " + + "plan_facility_linkage.active as plan_facility_active " + + "FROM plan_facility_linkage"; + + private static final String PLAN_FACILITY_SEARCH_QUERY_ORDER_BY_CLAUSE = " order by plan_facility_linkage.last_modified_time desc "; + + private static final String PLAN_FACILITY_SEARCH_QUERY_COUNT_WRAPPER = "SELECT COUNT(*) AS total_count FROM ( "; + + public String getPlanFacilitySearchQuery(PlanFacilitySearchCriteria planFacilitySearchCriteria, List preparedStmtList) { + String query = buildPlanFacilitySearchQuery(planFacilitySearchCriteria, preparedStmtList, Boolean.FALSE); + query = queryUtil.addOrderByClause(query, PLAN_FACILITY_SEARCH_QUERY_ORDER_BY_CLAUSE); + query = getPaginatedQuery(query, planFacilitySearchCriteria, preparedStmtList); + return query; + } + + /** + * Constructs the count query to get the total count of plan facilities based on search criteria. + * + * @param planFacilitySearchCriteria The criteria used for filtering PlanFacility objects. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A SQL query string to get the total count of plan facilities. + */ + public String getPlanFacilityCountQuery(PlanFacilitySearchCriteria planFacilitySearchCriteria, List preparedStmtList) { + String query = buildPlanFacilitySearchQuery(planFacilitySearchCriteria, preparedStmtList, Boolean.TRUE); + return query; + } + + private String buildPlanFacilitySearchQuery(PlanFacilitySearchCriteria planFacilitySearchCriteria, List preparedStmtList, boolean isCount) { + StringBuilder builder = new StringBuilder(PLAN_FACILITY_QUERY); + + if (!CollectionUtils.isEmpty(planFacilitySearchCriteria.getIds())) { + Set ids = planFacilitySearchCriteria.getIds(); + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" id IN ( ").append(queryUtil.createQuery(ids.size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, ids); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getTenantId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" tenant_id = ? "); + preparedStmtList.add(planFacilitySearchCriteria.getTenantId()); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getPlanConfigurationId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" plan_configuration_id = ? "); + preparedStmtList.add(planFacilitySearchCriteria.getPlanConfigurationId()); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getPlanConfigurationName())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" plan_configuration_name ILIKE ? "); + preparedStmtList.add(PERCENTAGE_WILDCARD + planFacilitySearchCriteria.getPlanConfigurationName() + PERCENTAGE_WILDCARD); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getFacilityId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" facility_id = ? "); + preparedStmtList.add(planFacilitySearchCriteria.getFacilityId()); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getFacilityName())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" facility_name ILIKE ? "); + preparedStmtList.add(PERCENTAGE_WILDCARD + planFacilitySearchCriteria.getFacilityName() + PERCENTAGE_WILDCARD); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getResidingBoundaries())) { + List residingBoundaries = planFacilitySearchCriteria.getResidingBoundaries(); + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" residing_boundary IN ( ").append(queryUtil.createQuery(residingBoundaries.size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, residingBoundaries); + } + + if (!CollectionUtils.isEmpty(planFacilitySearchCriteria.getJurisdiction())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ").append(queryUtil.createQuery(planFacilitySearchCriteria.getJurisdiction().size())).append(" ]::text[] "); + builder.append(" && string_to_array(boundary_ancestral_path, '|') "); + queryUtil.addToPreparedStatement(preparedStmtList, planFacilitySearchCriteria.getJurisdiction()); + } + + if(!CollectionUtils.isEmpty(planFacilitySearchCriteria.getFiltersMap())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" additional_details @> CAST( ? AS jsonb )"); + String partialQueryJsonString = queryUtil.preparePartialJsonStringFromFilterMap(planFacilitySearchCriteria.getFiltersMap()); + preparedStmtList.add(partialQueryJsonString); + } + + StringBuilder countQuery = new StringBuilder(); + if (isCount) { + countQuery.append(PLAN_FACILITY_SEARCH_QUERY_COUNT_WRAPPER).append(builder); + countQuery.append(") AS subquery"); + + return countQuery.toString(); + } + + return builder.toString(); + } + + private String getPaginatedQuery(String query, PlanFacilitySearchCriteria planFacilitySearchCriteria, List preparedStmtList) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(ObjectUtils.isEmpty(planFacilitySearchCriteria.getOffset()) ? config.getDefaultOffset() : planFacilitySearchCriteria.getOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(ObjectUtils.isEmpty(planFacilitySearchCriteria.getLimit()) ? config.getDefaultLimit() : planFacilitySearchCriteria.getLimit()); + + return paginatedQuery.toString(); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanQueryBuilder.java b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanQueryBuilder.java index 1b0adb59213..5c8bc91097b 100644 --- a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanQueryBuilder.java +++ b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanQueryBuilder.java @@ -6,6 +6,9 @@ import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; + +import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -14,13 +17,16 @@ public class PlanQueryBuilder { private Configuration config; - public PlanQueryBuilder(Configuration config) { + private QueryUtil queryUtil; + + public PlanQueryBuilder(Configuration config, QueryUtil queryUtil) { this.config = config; + this.queryUtil = queryUtil; } private static final String PLAN_SEARCH_BASE_QUERY = "SELECT id FROM plan "; - private static final String PLAN_QUERY = "SELECT plan.id as plan_id, plan.tenant_id as plan_tenant_id, plan.locality as plan_locality, plan.execution_plan_id as plan_execution_plan_id, plan.plan_configuration_id as plan_plan_configuration_id, plan.additional_details as plan_additional_details, plan.created_by as plan_created_by, plan.created_time as plan_created_time, plan.last_modified_by as plan_last_modified_by, plan.last_modified_time as plan_last_modified_time,\n" + + private static final String PLAN_QUERY = "SELECT plan.id as plan_id, plan.tenant_id as plan_tenant_id, plan.locality as plan_locality, plan.campaign_id as plan_campaign_id, plan.plan_configuration_id as plan_plan_configuration_id, plan.boundary_ancestral_path as plan_boundary_ancestral_path, plan.status as plan_status, plan.assignee as plan_assignee, plan.additional_details as plan_additional_details, plan.created_by as plan_created_by, plan.created_time as plan_created_time, plan.last_modified_by as plan_last_modified_by, plan.last_modified_time as plan_last_modified_time,\n" + "\t plan_activity.id as plan_activity_id, plan_activity.code as plan_activity_code, plan_activity.description as plan_activity_description, plan_activity.planned_start_date as plan_activity_planned_start_date, plan_activity.planned_end_date as plan_activity_planned_end_date, plan_activity.dependencies as plan_activity_dependencies, plan_activity.plan_id as plan_activity_plan_id, plan_activity.created_by as plan_activity_created_by, plan_activity.created_time as plan_activity_created_time, plan_activity.last_modified_by as plan_activity_last_modified_by, plan_activity.last_modified_time as plan_activity_last_modified_time,\n" + "\t plan_activity_condition.id as plan_activity_condition_id, plan_activity_condition.entity as plan_activity_condition_entity, plan_activity_condition.entity_property as plan_activity_condition_entity_property, plan_activity_condition.expression as plan_activity_condition_expression, plan_activity_condition.activity_id as plan_activity_condition_activity_id, plan_activity_condition.is_active as plan_activity_condition_is_active, plan_activity_condition.created_by as plan_activity_condition_created_by, plan_activity_condition.created_time as plan_activity_condition_created_time, plan_activity_condition.last_modified_by as plan_activity_condition_last_modified_by, plan_activity_condition.last_modified_time as plan_activity_condition_last_modified_time,\n" + "\t plan_resource.id as plan_resource_id, plan_resource.resource_type as plan_resource_resource_type, plan_resource.estimated_number as plan_resource_estimated_number, plan_resource.plan_id as plan_resource_plan_id, plan_resource.activity_code as plan_resource_activity_code, plan_resource.created_by as plan_resource_created_by, plan_resource.created_time as plan_resource_created_time, plan_resource.last_modified_by as plan_resource_last_modified_by, plan_resource.last_modified_time as plan_resource_last_modified_time,\n" + @@ -31,8 +37,14 @@ public PlanQueryBuilder(Configuration config) { "\t LEFT JOIN plan_resource ON plan.id = plan_resource.plan_id\n" + "\t LEFT JOIN plan_target ON plan.id = plan_target.plan_id"; + private static final String BULK_PLAN_UPDATE_QUERY = "UPDATE plan SET status = ?, assignee = ?, last_modified_by = ?, last_modified_time = ? WHERE id = ?"; + private static final String PLAN_SEARCH_QUERY_ORDER_BY_CLAUSE = " order by plan.last_modified_time desc "; + private static final String PLAN_SEARCH_QUERY_COUNT_WRAPPER = "SELECT COUNT(id) AS total_count FROM ( "; + + private static final String PLAN_STATUS_COUNT_QUERY = "SELECT COUNT(id) as plan_status_count, status FROM (SELECT id, status FROM plan {INTERNAL_QUERY}) as plan_status_map GROUP BY status"; + public String getPlanQuery(List ids, List preparedStmtList) { return buildPlanQuery(ids, preparedStmtList); } @@ -41,60 +53,137 @@ private String buildPlanQuery(List ids, List preparedStmtList) { StringBuilder builder = new StringBuilder(PLAN_QUERY); if (!CollectionUtils.isEmpty(ids)) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); - builder.append(" plan.id IN ( ").append(QueryUtil.createQuery(ids.size())).append(" )"); - QueryUtil.addToPreparedStatement(preparedStmtList, new LinkedHashSet<>(ids)); + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" plan.id IN ( ").append(queryUtil.createQuery(ids.size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, ids); } - return builder.toString(); + return queryUtil.addOrderByClause(builder.toString(), PLAN_SEARCH_QUERY_ORDER_BY_CLAUSE); } public String getPlanSearchQuery(PlanSearchCriteria planSearchCriteria, List preparedStmtList) { - String query = buildPlanSearchQuery(planSearchCriteria, preparedStmtList); - query = QueryUtil.addOrderByClause(query, PLAN_SEARCH_QUERY_ORDER_BY_CLAUSE); + String query = buildPlanSearchQuery(planSearchCriteria, preparedStmtList, Boolean.FALSE, Boolean.FALSE); + query = queryUtil.addOrderByClause(query, PLAN_SEARCH_QUERY_ORDER_BY_CLAUSE); query = getPaginatedQuery(query, planSearchCriteria, preparedStmtList); return query; } + /** + * Method to build a query to get the toatl count of plans based on the given search criteria + * + * @param criteria + * @param preparedStmtList + * @return + */ + public String getPlanCountQuery(PlanSearchCriteria criteria, List preparedStmtList) { + String query = buildPlanSearchQuery(criteria, preparedStmtList, Boolean.TRUE, Boolean.FALSE); + return query; + } + + /** + * Constructs the status count query to get the count of plans based on their current status for the given search criteria + * + * @param searchCriteria The criteria used for filtering Plans. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A SQL query string to get the status count of Plans for a given search criteria. + */ + public String getPlanStatusCountQuery(PlanSearchCriteria searchCriteria, List preparedStmtList) { + PlanSearchCriteria planSearchCriteria = PlanSearchCriteria.builder() + .tenantId(searchCriteria.getTenantId()) + .planConfigurationId(searchCriteria.getPlanConfigurationId()) + .campaignId(searchCriteria.getCampaignId()) + .jurisdiction(searchCriteria.getJurisdiction()) + .build(); + return buildPlanSearchQuery(planSearchCriteria, preparedStmtList, Boolean.FALSE, Boolean.TRUE); + } + /** * Method to build query dynamically based on the criteria passed to the method + * * @param planSearchCriteria * @param preparedStmtList * @return */ - private String buildPlanSearchQuery(PlanSearchCriteria planSearchCriteria, List preparedStmtList) { + private String buildPlanSearchQuery(PlanSearchCriteria planSearchCriteria, List preparedStmtList, boolean isCount, boolean isStatusCount) { StringBuilder builder = new StringBuilder(PLAN_SEARCH_BASE_QUERY); + if(isStatusCount) { + builder = new StringBuilder(); + } + if (!ObjectUtils.isEmpty(planSearchCriteria.getTenantId())) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); + queryUtil.addClauseIfRequired(builder, preparedStmtList); builder.append(" tenant_id = ? "); preparedStmtList.add(planSearchCriteria.getTenantId()); } if (!CollectionUtils.isEmpty(planSearchCriteria.getIds())) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); - builder.append(" id IN ( ").append(QueryUtil.createQuery(planSearchCriteria.getIds().size())).append(" )"); - QueryUtil.addToPreparedStatement(preparedStmtList, planSearchCriteria.getIds()); + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" id IN ( ").append(queryUtil.createQuery(planSearchCriteria.getIds().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, planSearchCriteria.getIds()); } - if (!ObjectUtils.isEmpty(planSearchCriteria.getLocality())) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); - builder.append(" locality = ? "); - preparedStmtList.add(planSearchCriteria.getLocality()); + if (!CollectionUtils.isEmpty(planSearchCriteria.getLocality())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" locality IN ( ").append(queryUtil.createQuery(planSearchCriteria.getLocality().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, planSearchCriteria.getLocality()); } - if (!ObjectUtils.isEmpty(planSearchCriteria.getExecutionPlanId())) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); - builder.append(" execution_plan_id = ? "); - preparedStmtList.add(planSearchCriteria.getExecutionPlanId()); + if (!ObjectUtils.isEmpty(planSearchCriteria.getCampaignId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" campaign_id = ? "); + preparedStmtList.add(planSearchCriteria.getCampaignId()); } if (!ObjectUtils.isEmpty(planSearchCriteria.getPlanConfigurationId())) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); + queryUtil.addClauseIfRequired(builder, preparedStmtList); builder.append(" plan_configuration_id = ? "); preparedStmtList.add(planSearchCriteria.getPlanConfigurationId()); } + if (!ObjectUtils.isEmpty(planSearchCriteria.getStatus())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" status = ? "); + preparedStmtList.add(planSearchCriteria.getStatus()); + } + + if (!ObjectUtils.isEmpty(planSearchCriteria.getAssignee())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" assignee = ? "); + preparedStmtList.add(planSearchCriteria.getAssignee()); + } + + if (!ObjectUtils.isEmpty(planSearchCriteria.getAssignee())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ").append(queryUtil.createQuery(Collections.singleton(planSearchCriteria.getAssignee()).size())).append(" ]").append("::text[] "); + builder.append(" && string_to_array(assignee, ',') "); + queryUtil.addToPreparedStatement(preparedStmtList, Collections.singleton(planSearchCriteria.getAssignee())); + } + + if (!CollectionUtils.isEmpty(planSearchCriteria.getJurisdiction())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ") + .append(queryUtil.createQuery(planSearchCriteria.getJurisdiction().size())) + .append(" ]::text[] "); + + builder.append(" && string_to_array(boundary_ancestral_path, '|') "); + queryUtil.addToPreparedStatement(preparedStmtList, planSearchCriteria.getJurisdiction()); + } + + + StringBuilder countQuery = new StringBuilder(); + if (isCount) { + + countQuery.append(PLAN_SEARCH_QUERY_COUNT_WRAPPER).append(builder); + countQuery.append(") AS subquery"); + + return countQuery.toString(); + } + + if (isStatusCount) { + return PLAN_STATUS_COUNT_QUERY.replace("{INTERNAL_QUERY}", builder); + } + return builder.toString(); } @@ -112,4 +201,7 @@ private String getPaginatedQuery(String query, PlanSearchCriteria planSearchCrit return paginatedQuery.toString(); } + public String getBulkPlanQuery() { + return BULK_PLAN_UPDATE_QUERY; + } } diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java index f8aebd12a9a..4645ce10b5e 100644 --- a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java @@ -1,33 +1,35 @@ package digit.repository.rowmapper; -import digit.web.models.Assumption; -import digit.web.models.File; -import digit.web.models.Operation; -import digit.web.models.PlanConfiguration; -import digit.web.models.ResourceMapping; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import digit.util.QueryUtil; +import digit.web.models.*; import org.egov.common.contract.models.AuditDetails; +import org.postgresql.util.PGobject; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + @Component public class PlanConfigRowMapper implements ResultSetExtractor> { + private QueryUtil queryUtil; + + public PlanConfigRowMapper(QueryUtil queryUtil) { + this.queryUtil = queryUtil; + } + @Override public List extractData(ResultSet rs) throws SQLException, DataAccessException { Map planConfigurationMap = new LinkedHashMap<>(); - Map fileMap = new LinkedHashMap<>(); - Map operationMap = new LinkedHashMap<>(); - Map assumptionMap = new LinkedHashMap<>(); - Map resourceMappingMap = new LinkedHashMap<>(); + Set fileSet = new HashSet<>(); + Set operationSet = new HashSet<>(); + Set assumptionSet = new HashSet<>(); + Set resourceMappingSet = new HashSet<>(); while (rs.next()) { @@ -37,6 +39,10 @@ public List extractData(ResultSet rs) throws SQLException, Da if (ObjectUtils.isEmpty(planConfigEntry)) { planConfigEntry = new PlanConfiguration(); + fileSet.clear(); + operationSet.clear(); + assumptionSet.clear(); + resourceMappingSet.clear(); // Prepare audit details AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("plan_configuration_created_by")).createdTime(rs.getLong("plan_configuration_created_time")).lastModifiedBy(rs.getString("plan_configuration_last_modified_by")).lastModifiedTime(rs.getLong("plan_configuration_last_modified_time")).build(); @@ -45,15 +51,16 @@ public List extractData(ResultSet rs) throws SQLException, Da planConfigEntry.setId(planConfigId); planConfigEntry.setTenantId(rs.getString("plan_configuration_tenant_id")); planConfigEntry.setName(rs.getString("plan_configuration_name")); - planConfigEntry.setExecutionPlanId(rs.getString("plan_configuration_execution_plan_id")); - planConfigEntry.setStatus(PlanConfiguration.StatusEnum.valueOf(rs.getString("plan_configuration_status").toUpperCase())); + planConfigEntry.setCampaignId(rs.getString("plan_configuration_campaign_id")); + planConfigEntry.setStatus(rs.getString("plan_configuration_status")); + planConfigEntry.setAdditionalDetails(queryUtil.getAdditionalDetail((PGobject) rs.getObject("plan_configuration_additional_details"))); planConfigEntry.setAuditDetails(auditDetails); } - addFiles(rs, planConfigEntry, fileMap); - addAssumptions(rs, planConfigEntry, assumptionMap); - addOperations(rs, planConfigEntry, operationMap); - addResourceMappings(rs, planConfigEntry, resourceMappingMap); + addFiles(rs, planConfigEntry, fileSet); + addAssumptions(rs, planConfigEntry, assumptionSet); + addOperations(rs, planConfigEntry, operationSet); + addResourceMappings(rs, planConfigEntry, resourceMappingSet); planConfigurationMap.put(planConfigId, planConfigEntry); } @@ -65,13 +72,13 @@ public List extractData(ResultSet rs) throws SQLException, Da * * @param rs The ResultSet containing the data. * @param planConfigEntry The PlanConfiguration entry to which the File object will be added. - * @param fileMap A map to keep track of added File objects. + * @param fileSet A set to keep track of added File objects. * @throws SQLException If an SQL error occurs. */ - private void addFiles(ResultSet rs, PlanConfiguration planConfigEntry, Map fileMap) throws SQLException { + private void addFiles(ResultSet rs, PlanConfiguration planConfigEntry, Set fileSet) throws SQLException { String fileId = rs.getString("plan_configuration_files_id"); - if (ObjectUtils.isEmpty(fileId) || fileMap.containsKey(fileId)) { + if (ObjectUtils.isEmpty(fileId) || fileSet.contains(fileId)) { return; } @@ -89,7 +96,7 @@ private void addFiles(ResultSet rs, PlanConfiguration planConfigEntry, Map assumptionMap) throws SQLException { + private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Set assumptionSet) throws SQLException { String assumptionId = rs.getString("plan_configuration_assumptions_id"); - if (ObjectUtils.isEmpty(assumptionId) || assumptionMap.containsKey(assumptionId)) { + if (ObjectUtils.isEmpty(assumptionId) || assumptionSet.contains(assumptionId)) { return; } @@ -113,6 +120,8 @@ private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Map assumption.setKey(rs.getString("plan_configuration_assumptions_key")); assumption.setValue(rs.getBigDecimal("plan_configuration_assumptions_value")); assumption.setActive(rs.getBoolean("plan_configuration_assumptions_active")); + assumption.setSource(Source.valueOf(rs.getString("plan_configuration_assumptions_source"))); + assumption.setCategory(rs.getString("plan_configuration_assumptions_category")); if (CollectionUtils.isEmpty(planConfigEntry.getAssumptions())) { List assumptionList = new ArrayList<>(); @@ -122,7 +131,7 @@ private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Map planConfigEntry.getAssumptions().add(assumption); } - assumptionMap.put(assumptionId, assumption); + assumptionSet.add(assumptionId); } /** @@ -130,13 +139,13 @@ private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Map * * @param rs The ResultSet containing the data. * @param planConfigEntry The PlanConfiguration entry to which the Operation object will be added. - * @param operationMap A map to keep track of added Operation objects. + * @param operationSet A set to keep track of added Operation objects. * @throws SQLException If an SQL error occurs. */ - private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Map operationMap) throws SQLException { + private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Set operationSet) throws SQLException { String operationId = rs.getString("plan_configuration_operations_id"); - if (ObjectUtils.isEmpty(operationId) || operationMap.containsKey(operationId)) { + if (ObjectUtils.isEmpty(operationId) || operationSet.contains(operationId)) { return; } @@ -147,6 +156,10 @@ private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Map< operation.setAssumptionValue(rs.getString("plan_configuration_operations_assumption_value")); operation.setOutput(rs.getString("plan_configuration_operations_output")); operation.setActive(rs.getBoolean("plan_configuration_operations_active")); + operation.setShowOnEstimationDashboard(rs.getBoolean("plan_configuration_operations_show_on_estimation_dashboard")); + operation.setSource(Source.valueOf(rs.getString("plan_configuration_operations_source"))); + operation.setCategory(rs.getString("plan_configuration_operations_category")); + operation.setExecutionOrder(rs.getInt("plan_configuration_execution_order")); if (CollectionUtils.isEmpty(planConfigEntry.getOperations())) { List operationList = new ArrayList<>(); @@ -156,7 +169,7 @@ private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Map< planConfigEntry.getOperations().add(operation); } - operationMap.put(operationId, operation); + operationSet.add(operationId); } /** @@ -164,13 +177,13 @@ private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Map< * * @param rs The ResultSet containing the data. * @param planConfigEntry The PlanConfiguration entry to which the ResourceMapping object will be added. - * @param mappingMap A map to keep track of added ResourceMapping objects. + * @param resourceMappingSet A set to keep track of added ResourceMapping objects. * @throws SQLException If an SQL error occurs. */ - private void addResourceMappings(ResultSet rs, PlanConfiguration planConfigEntry, Map mappingMap) throws SQLException { + private void addResourceMappings(ResultSet rs, PlanConfiguration planConfigEntry, Set resourceMappingSet) throws SQLException { String mappingId = rs.getString("plan_configuration_mapping_id"); - if (ObjectUtils.isEmpty(mappingId) || mappingMap.containsKey(mappingId)) { + if (ObjectUtils.isEmpty(mappingId) || resourceMappingSet.contains(mappingId)) { return; } @@ -189,7 +202,7 @@ private void addResourceMappings(ResultSet rs, PlanConfiguration planConfigEntry planConfigEntry.getResourceMapping().add(mapping); } - mappingMap.put(mappingId, mapping); + resourceMappingSet.add(mappingId); } } diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanEmployeeAssignmentRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanEmployeeAssignmentRowMapper.java new file mode 100644 index 00000000000..edf79b72c02 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanEmployeeAssignmentRowMapper.java @@ -0,0 +1,66 @@ +package digit.repository.rowmapper; + +import digit.util.QueryUtil; +import digit.web.models.PlanEmployeeAssignment; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.AuditDetails; +import org.postgresql.util.PGobject; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class PlanEmployeeAssignmentRowMapper implements ResultSetExtractor> { + + private QueryUtil queryUtil; + + public PlanEmployeeAssignmentRowMapper(QueryUtil queryUtil) { + this.queryUtil = queryUtil; + } + + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map planEmployeeAssignmentMap = new LinkedHashMap<>(); + + while (rs.next()) { + String planEmployeeAssignmentId = rs.getString("id"); + + PlanEmployeeAssignment planEmployeeAssignment = planEmployeeAssignmentMap.get(planEmployeeAssignmentId); + + if (ObjectUtils.isEmpty(planEmployeeAssignment)) { + planEmployeeAssignment = new PlanEmployeeAssignment(); + + // Prepare audit details + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("created_by")).createdTime(rs.getLong("created_time")).lastModifiedBy(rs.getString("last_modified_by")).lastModifiedTime(rs.getLong("last_modified_time")).build(); + + // Converting jurisdiction from comma separated string to a list of string + String jurisdiction = rs.getString("jurisdiction"); + Set jurisdictionList = Arrays.stream(jurisdiction.split(",")).collect(Collectors.toSet()); + + // Prepare PlanEmployeeAssignment object + planEmployeeAssignment.setId(planEmployeeAssignmentId); + planEmployeeAssignment.setTenantId(rs.getString("tenant_id")); + planEmployeeAssignment.setPlanConfigurationId(rs.getString("plan_configuration_id")); + planEmployeeAssignment.setPlanConfigurationName(rs.getString("plan_configuration_name")); + planEmployeeAssignment.setEmployeeId(rs.getString("employee_id")); + planEmployeeAssignment.setRole(rs.getString("role")); + planEmployeeAssignment.setHierarchyLevel(rs.getString("hierarchy_level")); + planEmployeeAssignment.setJurisdiction(jurisdictionList); + planEmployeeAssignment.setActive(rs.getBoolean("active")); + planEmployeeAssignment.setAdditionalDetails(queryUtil.getAdditionalDetail((PGobject) rs.getObject("additional_details"))); + planEmployeeAssignment.setAuditDetails(auditDetails); + + planEmployeeAssignmentMap.put(planEmployeeAssignmentId, planEmployeeAssignment); + } + } + + return new ArrayList<>(planEmployeeAssignmentMap.values()); + } +} diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanFacilityRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanFacilityRowMapper.java new file mode 100644 index 00000000000..c7ea2667ef1 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanFacilityRowMapper.java @@ -0,0 +1,79 @@ +package digit.repository.rowmapper; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.web.models.PlanFacility; +import org.egov.common.contract.models.AuditDetails; +import org.egov.tracer.model.CustomException; +import org.postgresql.util.PGobject; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +@Component +public class PlanFacilityRowMapper implements ResultSetExtractor> { + + private final ObjectMapper objectMapper; + + public PlanFacilityRowMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map planFacilityMap = new LinkedHashMap<>(); + while (rs.next()) { + String planFacilityId = rs.getString("plan_facility_id"); + + PlanFacility planFacilityEntry = planFacilityMap.get(planFacilityId); + if (planFacilityEntry == null || ObjectUtils.isEmpty(planFacilityEntry)) { + planFacilityEntry = new PlanFacility(); + + // Prepare audit details + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(rs.getString("plan_facility_created_by")) + .createdTime(rs.getLong("plan_facility_created_time")) + .lastModifiedBy(rs.getString("plan_facility_last_modified_by")) + .lastModifiedTime(rs.getLong("plan_facility_last_modified_time")) + .build(); + + // Prepare plan facility object + planFacilityEntry.setId(planFacilityId); + planFacilityEntry.setTenantId(rs.getString("plan_facility_tenant_id")); + planFacilityEntry.setPlanConfigurationId(rs.getString("plan_facility_plan_configuration_id")); + planFacilityEntry.setPlanConfigurationName(rs.getString("plan_facility_plan_configuration_name")); + planFacilityEntry.setFacilityId(rs.getString("plan_facility_facility_id")); + planFacilityEntry.setFacilityName(rs.getString("plan_facility_facility_name")); + planFacilityEntry.setResidingBoundary(rs.getString("plan_facility_residing_boundary")); + planFacilityEntry.setBoundaryAncestralPath(rs.getString("plan_facility_boundary_ancestral_path")); + String serviceBoundaries = rs.getString("plan_facility_service_boundaries"); + planFacilityEntry.setServiceBoundaries(ObjectUtils.isEmpty(serviceBoundaries) ? new ArrayList<>() : Arrays.asList(serviceBoundaries.split(","))); + planFacilityEntry.setAdditionalDetails(getAdditionalDetail((PGobject) rs.getObject("plan_facility_additional_details"))); + planFacilityEntry.setAuditDetails(auditDetails); + planFacilityEntry.setActive(rs.getBoolean("plan_facility_active")); + } + + planFacilityMap.put(planFacilityId, planFacilityEntry); + } + return new ArrayList<>(planFacilityMap.values()); + } + + private JsonNode getAdditionalDetail(PGobject pGobject) { + JsonNode additionalDetail = null; + + try { + if (!ObjectUtils.isEmpty(pGobject)) { + additionalDetail = objectMapper.readTree(pGobject.getValue()); + } + } catch (IOException e) { + throw new CustomException("PARSING_ERROR", "Failed to parse additionalDetails object"); + } + + return additionalDetail; + } +} diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java index a82919fed46..aa00207a741 100644 --- a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java @@ -1,10 +1,8 @@ package digit.repository.rowmapper; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import digit.util.QueryUtil; import digit.web.models.*; import org.egov.common.contract.models.AuditDetails; -import org.egov.tracer.model.CustomException; import org.postgresql.util.PGobject; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.ResultSetExtractor; @@ -12,7 +10,6 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; -import java.io.IOException; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; @@ -20,28 +17,32 @@ @Component public class PlanRowMapper implements ResultSetExtractor> { - private ObjectMapper objectMapper; + private QueryUtil queryUtil; - public PlanRowMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; + public PlanRowMapper(QueryUtil queryUtil) { + this.queryUtil = queryUtil; } @Override public List extractData(ResultSet rs) throws SQLException, DataAccessException { Map planMap = new LinkedHashMap<>(); Map activityMap = new LinkedHashMap<>(); - Map conditionMap = new LinkedHashMap<>(); - Map resourceMap = new LinkedHashMap<>(); - Map targetMap = new LinkedHashMap<>(); + Set conditionSet = new HashSet<>(); + Set resourceSet = new HashSet<>(); + Set targetSet = new HashSet<>(); // Traverse through result set and create plan objects - while(rs.next()) { + while (rs.next()) { String planId = rs.getString("plan_id"); Plan planEntry = planMap.get(planId); - if(ObjectUtils.isEmpty(planEntry)) { + if (ObjectUtils.isEmpty(planEntry)) { planEntry = new Plan(); + activityMap.clear(); + conditionSet.clear(); + resourceSet.clear(); + targetSet.clear(); // Prepare audit details AuditDetails auditDetails = AuditDetails.builder() @@ -51,20 +52,26 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExcep .lastModifiedTime(rs.getLong("plan_last_modified_time")) .build(); + String commaSeparatedAssignee = rs.getString("plan_assignee"); + List assignee = !ObjectUtils.isEmpty(commaSeparatedAssignee) ? Arrays.asList(commaSeparatedAssignee.split(",")) : null; + // Prepare plan object planEntry.setId(planId); planEntry.setTenantId(rs.getString("plan_tenant_id")); planEntry.setLocality(rs.getString("plan_locality")); - planEntry.setExecutionPlanId(rs.getString("plan_execution_plan_id")); + planEntry.setCampaignId(rs.getString("plan_campaign_id")); + planEntry.setStatus(rs.getString("plan_status")); + planEntry.setAssignee(assignee); planEntry.setPlanConfigurationId(rs.getString("plan_plan_configuration_id")); - planEntry.setAdditionalDetails(getAdditionalDetail((PGobject) rs.getObject("plan_additional_details"))); + planEntry.setBoundaryAncestralPath(rs.getString("plan_boundary_ancestral_path")); + planEntry.setAdditionalDetails(queryUtil.getAdditionalDetail((PGobject) rs.getObject("plan_additional_details"))); planEntry.setAuditDetails(auditDetails); } - addActivities(rs, planEntry, activityMap, conditionMap); - addResources(rs, planEntry, resourceMap); - addTargets(rs, planEntry, targetMap); + addActivities(rs, planEntry, activityMap, conditionSet); + addResources(rs, planEntry, resourceSet); + addTargets(rs, planEntry, targetSet); planMap.put(planId, planEntry); } @@ -72,15 +79,14 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExcep } private void addActivities(ResultSet rs, Plan plan, - Map activityMap, Map conditionMap) throws SQLException, DataAccessException { + Map activityMap, Set conditionSet) throws SQLException, DataAccessException { String activityId = rs.getString("plan_activity_id"); - if(!ObjectUtils.isEmpty(activityId) && activityMap.containsKey(activityId)) { - addActivityConditions(rs, activityMap.get(activityId), conditionMap); + if (!ObjectUtils.isEmpty(activityId) && activityMap.containsKey(activityId)) { + addActivityConditions(rs, activityMap.get(activityId), conditionSet); return; - } - else if (ObjectUtils.isEmpty(activityId)) { + } else if (ObjectUtils.isEmpty(activityId)) { // Set activities list to empty if no activity found plan.setActivities(new ArrayList<>()); return; @@ -103,7 +109,7 @@ else if (ObjectUtils.isEmpty(activityId)) { .dependencies(ObjectUtils.isEmpty(dependencies) ? new ArrayList<>() : Arrays.asList(rs.getString("plan_activity_dependencies").split(","))) .build(); - addActivityConditions(rs, activity, conditionMap); + addActivityConditions(rs, activity, conditionSet); if (CollectionUtils.isEmpty(plan.getActivities())) { List activityList = new ArrayList<>(); @@ -117,10 +123,10 @@ else if (ObjectUtils.isEmpty(activityId)) { } - private void addActivityConditions(ResultSet rs, Activity activity, Map conditionMap) throws SQLException, DataAccessException { + private void addActivityConditions(ResultSet rs, Activity activity, Set conditionSet) throws SQLException, DataAccessException { String conditionId = rs.getString("plan_activity_condition_id"); - if(ObjectUtils.isEmpty(conditionId) || conditionMap.containsKey(conditionId)) { + if (ObjectUtils.isEmpty(conditionId) || conditionSet.contains(conditionId)) { List conditionList = new ArrayList<>(); activity.setConditions(conditionList); return; @@ -140,7 +146,7 @@ private void addActivityConditions(ResultSet rs, Activity activity, Map conditionList = new ArrayList<>(); conditionList.add(condition); activity.setConditions(conditionList); @@ -148,15 +154,15 @@ private void addActivityConditions(ResultSet rs, Activity activity, Map resourceMap) throws SQLException, DataAccessException { + private void addResources(ResultSet rs, Plan planEntry, Set resourceSet) throws SQLException, DataAccessException { String resourceId = rs.getString("plan_resource_id"); - if(ObjectUtils.isEmpty(resourceId) || resourceMap.containsKey(resourceId)) { + if (ObjectUtils.isEmpty(resourceId) || resourceSet.contains(resourceId)) { List resourceList = new ArrayList<>(); planEntry.setResources(resourceList); return; @@ -184,14 +190,14 @@ private void addResources(ResultSet rs, Plan planEntry, Map re planEntry.getResources().add(resource); } - resourceMap.put(resource.getId(), resource); + resourceSet.add(resource.getId()); } - private void addTargets(ResultSet rs, Plan planEntry, Map targetMap) throws SQLException, DataAccessException { + private void addTargets(ResultSet rs, Plan planEntry, Set targetSet) throws SQLException, DataAccessException { String targetId = rs.getString("plan_target_id"); - if(ObjectUtils.isEmpty(targetId) || targetMap.containsKey(targetId)) { + if (ObjectUtils.isEmpty(targetId) || targetSet.contains(targetId)) { List targetList = new ArrayList<>(); planEntry.setTargets(targetList); return; @@ -225,23 +231,7 @@ private void addTargets(ResultSet rs, Plan planEntry, Map target planEntry.getTargets().add(target); } - targetMap.put(target.getId(), target); - - } - - private JsonNode getAdditionalDetail(PGobject pGobject){ - JsonNode additionalDetail = null; + targetSet.add(target.getId()); - try { - if(ObjectUtils.isEmpty(pGobject)){ - additionalDetail = objectMapper.readTree(pGobject.getValue()); - } - } - catch (IOException e){ - throw new CustomException("PARSING_ERROR", "Failed to parse additionalDetails object"); - } - - return additionalDetail; } - } diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanStatusCountRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanStatusCountRowMapper.java new file mode 100644 index 00000000000..11e14d37763 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanStatusCountRowMapper.java @@ -0,0 +1,31 @@ +package digit.repository.rowmapper; + +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +@Component +public class PlanStatusCountRowMapper implements ResultSetExtractor> { + + @Override + public Map extractData(ResultSet rs) throws SQLException, DataAccessException { + + Map statusCountMap = new HashMap<>(); + + while (rs.next()) { + String status = rs.getString("status"); + Integer statusCount = rs.getInt("plan_status_count"); + + if(!ObjectUtils.isEmpty(status)) + statusCountMap.put(status, statusCount); + } + + return statusCountMap; + } +} diff --git a/health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java b/health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java index 303d9477e70..c9602b1a543 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java @@ -1,85 +1,99 @@ package digit.service; -import digit.config.Configuration; -import digit.kafka.Producer; -import digit.repository.impl.PlanConfigurationRepositoryImpl; +import digit.repository.PlanConfigurationRepository; import digit.service.enrichment.EnrichmentService; import digit.service.validator.PlanConfigurationValidator; +import digit.service.validator.WorkflowValidator; +import digit.service.workflow.WorkflowService; +import digit.util.CommonUtil; import digit.util.ResponseInfoFactory; +import digit.web.models.PlanConfiguration; import digit.web.models.PlanConfigurationRequest; import digit.web.models.PlanConfigurationResponse; import digit.web.models.PlanConfigurationSearchRequest; -import java.util.Collections; import lombok.extern.slf4j.Slf4j; import org.egov.common.utils.ResponseInfoUtil; import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.List; + @Service @Slf4j public class PlanConfigurationService { - private Producer producer; - private EnrichmentService enrichmentService; - private Configuration config; - private PlanConfigurationValidator validator; - private PlanConfigurationRepositoryImpl repository; + private PlanConfigurationRepository repository; private ResponseInfoFactory responseInfoFactory; - public PlanConfigurationService(Producer producer, EnrichmentService enrichmentService, Configuration config - , PlanConfigurationValidator validator, PlanConfigurationRepositoryImpl repository, ResponseInfoFactory responseInfoFactory) { - this.producer = producer; + private WorkflowValidator workflowValidator; + + private WorkflowService workflowService; + + private CommonUtil commonUtil; + + public PlanConfigurationService(EnrichmentService enrichmentService, PlanConfigurationValidator validator, PlanConfigurationRepository repository, ResponseInfoFactory responseInfoFactory, WorkflowService workflowService, WorkflowValidator workflowValidator, CommonUtil commonUtil) { this.enrichmentService = enrichmentService; - this.config = config; this.validator = validator; this.repository = repository; this.responseInfoFactory = responseInfoFactory; + this.workflowService = workflowService; + this.workflowValidator = workflowValidator; + this.commonUtil = commonUtil; } /** * Creates a new plan configuration based on the provided request. + * * @param request The request containing the plan configuration details. * @return The created plan configuration request. */ - public PlanConfigurationRequest create(PlanConfigurationRequest request) { + public PlanConfigurationResponse create(PlanConfigurationRequest request) { enrichmentService.enrichPlanConfigurationBeforeValidation(request); validator.validateCreate(request); enrichmentService.enrichCreate(request); repository.create(request); - return request; + + return PlanConfigurationResponse.builder() + .planConfiguration(Collections.singletonList(request.getPlanConfiguration())) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .build(); } /** * Searches for plan configurations based on the provided search criteria. + * * @param request The search request containing the criteria. * @return A list of plan configurations that match the search criteria. */ public PlanConfigurationResponse search(PlanConfigurationSearchRequest request) { validator.validateSearchRequest(request); - PlanConfigurationResponse response = PlanConfigurationResponse.builder(). + List planConfigurations = repository.search(request.getPlanConfigurationSearchCriteria()); + commonUtil.sortOperationsByExecutionOrder(planConfigurations); + return PlanConfigurationResponse.builder(). responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) - .planConfiguration(repository.search(request.getPlanConfigurationSearchCriteria())) + .planConfiguration(planConfigurations) .totalCount(repository.count(request.getPlanConfigurationSearchCriteria())) .build(); - - return response; } /** * Updates an existing plan configuration based on the provided request. + * * @param request The request containing the updated plan configuration details. * @return The response containing the updated plan configuration. */ public PlanConfigurationResponse update(PlanConfigurationRequest request) { validator.validateUpdateRequest(request); enrichmentService.enrichUpdate(request); + workflowValidator.validateWorkflow(request); + workflowService.invokeWorkflowForStatusUpdate(request); repository.update(request); - // Build and return response back to controller return PlanConfigurationResponse.builder() .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(request.getRequestInfo(), Boolean.TRUE)) .planConfiguration(Collections.singletonList(request.getPlanConfiguration())) diff --git a/health-services/plan-service/src/main/java/digit/service/PlanEmployeeService.java b/health-services/plan-service/src/main/java/digit/service/PlanEmployeeService.java new file mode 100644 index 00000000000..afa9ee46f38 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/PlanEmployeeService.java @@ -0,0 +1,91 @@ +package digit.service; + +import digit.config.Configuration; +import digit.kafka.Producer; +import digit.repository.PlanEmployeeAssignmentRepository; +import digit.service.enrichment.PlanEmployeeAssignmentEnricher; +import digit.service.validator.PlanEmployeeAssignmentValidator; +import digit.util.ResponseInfoFactory; +import digit.web.models.*; +import org.egov.common.utils.ResponseInfoUtil; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + +@Service +public class PlanEmployeeService { + + Producer producer; + + Configuration config; + + ResponseInfoFactory responseInfoFactory; + + PlanEmployeeAssignmentRepository repository; + + PlanEmployeeAssignmentEnricher enricher; + + PlanEmployeeAssignmentValidator validator; + + public PlanEmployeeService(Producer producer, Configuration config, ResponseInfoFactory responseInfoFactory, PlanEmployeeAssignmentRepository repository, PlanEmployeeAssignmentEnricher enricher, PlanEmployeeAssignmentValidator validator) { + this.producer = producer; + this.config = config; + this.responseInfoFactory = responseInfoFactory; + this.repository = repository; + this.enricher = enricher; + this.validator = validator; + } + + /** + * Creates a new plan employee assignment based on the provided request. + * + * @param request The request containing the plan employee assignment details. + * @return The response containing the created plan employee assignment. + */ + public PlanEmployeeAssignmentResponse create(PlanEmployeeAssignmentRequest request) { + validator.validateCreate(request); + enricher.enrichCreate(request); + repository.create(request); + + return PlanEmployeeAssignmentResponse.builder() + .planEmployeeAssignment(Collections.singletonList(request.getPlanEmployeeAssignment())) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), Boolean.TRUE)) + .build(); + } + + /** + * Searches for plan employee assignment based on the provided search criteria. + * + * @param request The search request containing the criteria. + * @return A list of plan employee assignments that matches the search criteria. + */ + public PlanEmployeeAssignmentResponse search(PlanEmployeeAssignmentSearchRequest request) { + // Delegate search request to repository + List planEmployeeAssignmentList = repository.search(request.getPlanEmployeeAssignmentSearchCriteria()); + + // Build and return response back to controller + return PlanEmployeeAssignmentResponse.builder() + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), Boolean.TRUE)) + .planEmployeeAssignment(planEmployeeAssignmentList) + .totalCount(repository.count(request.getPlanEmployeeAssignmentSearchCriteria())) + .build(); + } + + /** + * Updates an existing plan employee assignment based on the provided request. + * + * @param request The request containing the updated plan employee assignment details. + * @return The response containing the updated plan employee assignment. + */ + public PlanEmployeeAssignmentResponse update(PlanEmployeeAssignmentRequest request) { + validator.validateUpdate(request); + enricher.enrichUpdate(request); + repository.update(request); + + return PlanEmployeeAssignmentResponse.builder() + .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(request.getRequestInfo(), Boolean.TRUE)) + .planEmployeeAssignment(Collections.singletonList(request.getPlanEmployeeAssignment())) + .build(); + } +} diff --git a/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java b/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java index 75d79c840a3..b01c78ea82a 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java @@ -1,16 +1,18 @@ package digit.service; +import digit.web.models.Plan; import digit.web.models.PlanRequest; +import digit.web.models.boundary.BoundaryTypeHierarchy; +import digit.web.models.boundary.BoundaryTypeHierarchyDefinition; +import digit.web.models.boundary.EnrichedBoundary; +import digit.web.models.boundary.HierarchyRelation; import org.egov.common.utils.AuditDetailsEnrichmentUtil; import org.egov.common.utils.UUIDEnrichmentUtil; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; @Component public class PlanEnricher { @@ -105,5 +107,125 @@ public void enrichPlanUpdate(PlanRequest body) { } }); + // Enriching last modified time for update + body.getPlan().getAuditDetails().setLastModifiedTime(System.currentTimeMillis()); + } + + /** + * Enriches the boundary ancestral path and jurisdiction mapping for the provided boundary code in the plan request. + * + * @param plan The plan record whose boundary ancestral path has to be enriched. + * @param tenantBoundary boundary relationship from the boundary service for the given boundary code. + */ + public void enrichBoundaryAncestralPath(Plan plan, HierarchyRelation tenantBoundary) { + EnrichedBoundary boundary = tenantBoundary.getBoundary().get(0); + Map jurisdictionMapping = new LinkedHashMap<>(); + + StringBuilder boundaryAncestralPath = new StringBuilder(boundary.getCode()); + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + + // Iterate through the child boundary until there are no more + while (!CollectionUtils.isEmpty(boundary.getChildren())) { + boundary = boundary.getChildren().get(0); + boundaryAncestralPath.append("|").append(boundary.getCode()); + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + } + + // Setting the boundary ancestral path for the provided boundary + plan.setBoundaryAncestralPath(boundaryAncestralPath.toString()); + + // Setting jurisdiction mapping for the provided boundary + plan.setJurisdictionMapping(jurisdictionMapping); + } + + /** + * Helper method to enrich boundary hierarchy mapping. + * Creates a mapping of parentBoundaryType to childBoundaryType from the boundaryTypeHierarchy search response. + * + * @param boundaryTypeHierarchyDef Search response from boundary hierarchy search. + * @param boundaryHierarchyMapping boundary hierarchy map to be enriched. + * @return returns the highest boundary hierarchy for the given hierarchy type. + */ + private String getBoundaryHierarchyMapping(BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef, Map boundaryHierarchyMapping) { + String highestBoundaryHierarchy = null; + + for (BoundaryTypeHierarchy boundaryTypeHierarchy : boundaryTypeHierarchyDef.getBoundaryHierarchy()) { + if (ObjectUtils.isEmpty(boundaryTypeHierarchy.getParentBoundaryType())) + highestBoundaryHierarchy = boundaryTypeHierarchy.getBoundaryType(); + else + boundaryHierarchyMapping.put(boundaryTypeHierarchy.getParentBoundaryType(), boundaryTypeHierarchy.getBoundaryType()); + } + + return highestBoundaryHierarchy; + } + + /** + * Enriches jurisdiction mapping in plan for the given boundary ancestral path. + * + * @param plan plan with boundary ancestral path. + * @param boundaryTypeHierarchyDef boundary hierarchy for the given hierarchy type. + */ + public void enrichJurisdictionMapping(Plan plan, BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef) { + Map boundaryHierarchyMapping = new HashMap<>(); + + // Enriches the boundaryHierarchyMapping and returns the highest boundary hierarchy for the given hierarchy type. + String highestBoundaryHierarchy = getBoundaryHierarchyMapping(boundaryTypeHierarchyDef, boundaryHierarchyMapping); + + Map jurisdictionMapping = new LinkedHashMap<>(); + String boundaryHierarchy = highestBoundaryHierarchy; + + // Get the list of boundary codes from pipe separated boundaryAncestralPath. + List boundaryCode = getBoundaryCodeFromAncestralPath(plan.getBoundaryAncestralPath()); + + // Creates the mapping of boundary hierarchy with the corresponding boundary code. + for (String boundary : boundaryCode) { + jurisdictionMapping.put(boundaryHierarchy, boundary); + boundaryHierarchy = boundaryHierarchyMapping.get(boundaryHierarchy); + } + + plan.setJurisdictionMapping(jurisdictionMapping); + } + + /** + * Enriches jurisdiction mapping for the list of plans for the given boundary ancestral path. + * + * @param planList list of plans with boundary ancestral paths. + * @param boundaryTypeHierarchyDef boundary hierarchy for the given hierarchy type. + */ + public void enrichJurisdictionMapping(List planList, BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef) { + Map boundaryHierarchyMapping = new HashMap<>(); + + // Enriches the boundaryHierarchyMapping and returns the highest boundary hierarchy for the given hierarchy type. + String highestBoundaryHierarchy = getBoundaryHierarchyMapping(boundaryTypeHierarchyDef, boundaryHierarchyMapping); + + for (Plan plan : planList) { + + Map jurisdictionMapping = new LinkedHashMap<>(); + String boundaryHierarchy = highestBoundaryHierarchy; + + // Get the list of boundary codes from pipe separated boundaryAncestralPath. + List boundaryCode = getBoundaryCodeFromAncestralPath(plan.getBoundaryAncestralPath()); + + // Creates the mapping of boundary hierarchy with the corresponding boundary code. + for (String boundary : boundaryCode) { + jurisdictionMapping.put(boundaryHierarchy, boundary); + boundaryHierarchy = boundaryHierarchyMapping.get(boundaryHierarchy); + } + + plan.setJurisdictionMapping(jurisdictionMapping); + } + } + + /** + * Converts the boundaryAncestral path from a pipe separated string to an array of boundary codes. + * + * @param boundaryAncestralPath pipe separated boundaryAncestralPath. + * @return a list of boundary codes. + */ + private List getBoundaryCodeFromAncestralPath(String boundaryAncestralPath) { + if (ObjectUtils.isEmpty(boundaryAncestralPath)) { + return Collections.emptyList(); + } + return Arrays.asList(boundaryAncestralPath.split("\\|")); } } diff --git a/health-services/plan-service/src/main/java/digit/service/PlanFacilityService.java b/health-services/plan-service/src/main/java/digit/service/PlanFacilityService.java new file mode 100644 index 00000000000..8282a0fea74 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/PlanFacilityService.java @@ -0,0 +1,98 @@ +package digit.service; + +import digit.repository.PlanFacilityRepository; +import digit.service.enrichment.PlanFacilityEnricher; +import digit.service.validator.PlanFacilityValidator; +import digit.util.ResponseInfoFactory; +import digit.web.models.PlanFacility; +import digit.web.models.PlanFacilityRequest; +import digit.web.models.PlanFacilityResponse; +import org.egov.common.utils.ResponseInfoUtil; +import digit.web.models.PlanFacilitySearchRequest; +import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.List; + +@Service +public class PlanFacilityService { + + private PlanFacilityValidator planFacilityValidator; + private ResponseInfoFactory responseInfoFactory; + private PlanFacilityEnricher planFacilityEnricher; + private PlanFacilityRepository planFacilityRepository; + + public PlanFacilityService(PlanFacilityValidator planFacilityValidator, ResponseInfoFactory responseInfoFactory, PlanFacilityEnricher planFacilityEnricher, PlanFacilityRepository planFacilityRepository) { + this.planFacilityValidator = planFacilityValidator; + this.responseInfoFactory = responseInfoFactory; + this.planFacilityEnricher = planFacilityEnricher; + this.planFacilityRepository = planFacilityRepository; + } + + /** + * This method processes the requests that come for creating plan facilities. + * + * @param planFacilityRequest The PlanFacilityRequest containing the plan facility details for creation. + * @return PlanFacilityResponse containing the created plan facility and response information. + */ + public PlanFacilityResponse createPlanFacility(PlanFacilityRequest planFacilityRequest) { + // Validate plan facility create request + planFacilityValidator.validatePlanFacilityCreate(planFacilityRequest); + + // Enrich plan facility create request + planFacilityEnricher.enrichPlanFacilityCreate(planFacilityRequest); + + // Delegate creation request to repository + planFacilityRepository.create(planFacilityRequest); + + // Build and return response back to controller + return PlanFacilityResponse.builder() + .planFacility(Collections.singletonList(planFacilityRequest.getPlanFacility())) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(planFacilityRequest.getRequestInfo(), Boolean.TRUE)) + .build(); + } + + /** + * This method processes the requests that come for searching plan facilities. + * + * @param planFacilitySearchRequest containing the search criteria and request information. + * @return PlanFacilityResponse object containing the search results and response information. + */ + public PlanFacilityResponse searchPlanFacility(PlanFacilitySearchRequest planFacilitySearchRequest) { + // Enrich search request + planFacilityEnricher.enrichSearchRequest(planFacilitySearchRequest); + + // Delegate request to repository + List planFacilityList = planFacilityRepository.search(planFacilitySearchRequest.getPlanFacilitySearchCriteria()); + + // Build and return response back to controller + return PlanFacilityResponse.builder() + .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(planFacilitySearchRequest.getRequestInfo(), Boolean.TRUE)) + .planFacility(planFacilityList) + .totalCount(planFacilityRepository.count(planFacilitySearchRequest.getPlanFacilitySearchCriteria())) + .build(); + } + + /** + * Processes requests for updating plan facilities. + * + * @param planFacilityRequest The PlanFacilityRequest containing the update information. + * @return PlanFacilityResponse containing the updated plan facility and response information. + */ + public PlanFacilityResponse updatePlanFacility(PlanFacilityRequest planFacilityRequest) { + //validate plan facility request + planFacilityValidator.validatePlanFacilityUpdate(planFacilityRequest); + + //enrich plan facility request + planFacilityEnricher.enrichPlanFacilityUpdate(planFacilityRequest); + + //delegate update request to repository + planFacilityRepository.update(planFacilityRequest); + + //Build and return response back to controller + return PlanFacilityResponse.builder(). + responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(planFacilityRequest.getRequestInfo(), Boolean.TRUE)). + planFacility(Collections.singletonList(planFacilityRequest.getPlanFacility())). + build(); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/service/PlanService.java b/health-services/plan-service/src/main/java/digit/service/PlanService.java index c0c97a30eaf..4acaf58218b 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanService.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanService.java @@ -1,16 +1,16 @@ package digit.service; import digit.repository.PlanRepository; -import digit.web.models.Plan; -import digit.web.models.PlanRequest; -import digit.web.models.PlanResponse; -import digit.web.models.PlanSearchRequest; +import digit.service.workflow.WorkflowService; +import digit.web.models.*; +import org.egov.common.contract.response.ResponseInfo; import org.egov.common.utils.ResponseInfoUtil; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; @Service public class PlanService { @@ -21,10 +21,13 @@ public class PlanService { private PlanRepository planRepository; - public PlanService(PlanValidator planValidator, PlanEnricher planEnricher, PlanRepository planRepository) { + private WorkflowService workflowService; + + public PlanService(PlanValidator planValidator, PlanEnricher planEnricher, PlanRepository planRepository, WorkflowService workflowService) { this.planValidator = planValidator; this.planEnricher = planEnricher; this.planRepository = planRepository; + this.workflowService = workflowService; } /** @@ -39,6 +42,9 @@ public PlanResponse createPlan(PlanRequest body) { // Enrich plan create request planEnricher.enrichPlanCreate(body); + // Call workflow transition API for status update + workflowService.invokeWorkflowForStatusUpdate(body); + // Delegate creation request to repository planRepository.create(body); @@ -58,10 +64,18 @@ public PlanResponse searchPlan(PlanSearchRequest body) { // Delegate search request to repository List planList = planRepository.search(body.getPlanSearchCriteria()); + // Get the total count of plans for given search criteria + Integer count = planRepository.count(body.getPlanSearchCriteria()); + + // Get the status count of plans for given search criteria + Map statusCountMap = planRepository.statusCount(body); + // Build and return response back to controller return PlanResponse.builder() .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(body.getRequestInfo(), Boolean.TRUE)) .plan(planList) + .totalCount(count) + .statusCount(statusCountMap) .build(); } @@ -77,6 +91,9 @@ public PlanResponse updatePlan(PlanRequest body) { // Enrich plan update request planEnricher.enrichPlanUpdate(body); + // Call workflow transition API for status update + workflowService.invokeWorkflowForStatusUpdate(body); + // Delegate update request to repository planRepository.update(body); @@ -86,4 +103,25 @@ public PlanResponse updatePlan(PlanRequest body) { .plan(Collections.singletonList(body.getPlan())) .build(); } + + /** + * This method processes bulk update requests for plan. + * @param bulkPlanRequest + * @return + */ + public PlanResponse bulkUpdate(BulkPlanRequest bulkPlanRequest) { + // Validate bulk plan update request + planValidator.validateBulkPlanUpdate(bulkPlanRequest); + + // Call workflow transition for updating status and assignee + workflowService.invokeWorkflowForStatusUpdate(bulkPlanRequest); + + // Delegate bulk update request to repository + planRepository.bulkUpdate(bulkPlanRequest); + + // Build and return response back to controller + return PlanResponse.builder().responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(bulkPlanRequest.getRequestInfo(), Boolean.TRUE)) + .plan(bulkPlanRequest.getPlans()) + .build(); + } } diff --git a/health-services/plan-service/src/main/java/digit/service/PlanValidator.java b/health-services/plan-service/src/main/java/digit/service/PlanValidator.java index b52c3450c6d..cd9a6e9ba5d 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanValidator.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanValidator.java @@ -1,32 +1,28 @@ package digit.service; import com.jayway.jsonpath.JsonPath; +import digit.config.Configuration; import digit.repository.PlanConfigurationRepository; import digit.repository.PlanRepository; +import digit.util.BoundaryUtil; +import digit.util.CampaignUtil; +import digit.util.CommonUtil; import digit.util.MdmsUtil; import digit.web.models.*; +import digit.web.models.boundary.BoundarySearchResponse; +import digit.web.models.boundary.BoundaryTypeHierarchyResponse; +import digit.web.models.boundary.HierarchyRelation; +import digit.web.models.projectFactory.CampaignResponse; +import org.egov.common.utils.MultiStateInstanceUtil; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; -import static digit.config.ServiceConstants.INVALID_PLAN_CONFIG_ID_CODE; -import static digit.config.ServiceConstants.INVALID_PLAN_CONFIG_ID_MESSAGE; -import static digit.config.ServiceConstants.JSONPATH_ERROR_CODE; -import static digit.config.ServiceConstants.JSONPATH_ERROR_MESSAGE; -import static digit.config.ServiceConstants.MDMS_MASTER_METRIC; -import static digit.config.ServiceConstants.MDMS_MASTER_UOM; -import static digit.config.ServiceConstants.MDMS_PLAN_MODULE_NAME; -import static digit.config.ServiceConstants.METRIC_NOT_FOUND_IN_MDMS_CODE; -import static digit.config.ServiceConstants.METRIC_NOT_FOUND_IN_MDMS_MESSAGE; -import static digit.config.ServiceConstants.METRIC_UNIT_NOT_FOUND_IN_MDMS_CODE; -import static digit.config.ServiceConstants.METRIC_UNIT_NOT_FOUND_IN_MDMS_MESSAGE; +import static digit.config.ServiceConstants.*; @Component public class PlanValidator { @@ -37,19 +33,49 @@ public class PlanValidator { private MdmsUtil mdmsUtil; - public PlanValidator(PlanRepository planRepository, PlanConfigurationRepository planConfigurationRepository, MdmsUtil mdmsUtil) { + private MultiStateInstanceUtil centralInstanceUtil; + + private CommonUtil commonUtil; + + private CampaignUtil campaignUtil; + + private PlanEmployeeService planEmployeeService; + + private Configuration config; + + private PlanEnricher planEnricher; + + private BoundaryUtil boundaryUtil; + + public PlanValidator(PlanRepository planRepository, PlanConfigurationRepository planConfigurationRepository, MdmsUtil mdmsUtil, MultiStateInstanceUtil centralInstanceUtil, CommonUtil commonUtil, CampaignUtil campaignUtil, PlanEmployeeService planEmployeeService, Configuration config, PlanEnricher planEnricher, BoundaryUtil boundaryUtil) { this.planRepository = planRepository; this.planConfigurationRepository = planConfigurationRepository; this.mdmsUtil = mdmsUtil; + this.centralInstanceUtil = centralInstanceUtil; + this.commonUtil = commonUtil; + this.campaignUtil = campaignUtil; + this.planEmployeeService = planEmployeeService; + this.config = config; + this.planEnricher = planEnricher; + this.boundaryUtil = boundaryUtil; } /** * This method performs business validations on plan create requests + * * @param request */ public void validatePlanCreate(PlanRequest request) { - String rootTenantId = request.getPlan().getTenantId().split("\\.")[0]; + String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlan().getTenantId()); Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(request.getRequestInfo(), request.getPlan().getCampaignId(), rootTenantId); + BoundarySearchResponse boundarySearchResponse = boundaryUtil.fetchBoundaryData(request.getRequestInfo(), request.getPlan().getLocality(), request.getPlan().getTenantId(), campaignResponse.getCampaignDetails().get(0).getHierarchyType(), Boolean.TRUE, Boolean.FALSE); + + //TODO: remove after setting the flag in consumer + request.getPlan().setRequestFromResourceEstimationConsumer(Boolean.TRUE); + + // Validate locality against boundary service + validateBoundaryCode(boundarySearchResponse, request.getPlan()); // Validate activities validateActivities(request); @@ -74,10 +100,32 @@ public void validatePlanCreate(PlanRequest request) { // Validate Metric Detail's Unit against MDMS validateMetricDetailUnit(request, mdmsData); + + // Validate if campaign id exists against project factory + validateCampaignId(campaignResponse); + + // Validate the user information in the request + commonUtil.validateUserInfo(request.getRequestInfo()); + + // Validate plan-employee assignment and jurisdiction is request is from Resource Estimation Consumer + if(!request.getPlan().isRequestFromResourceEstimationConsumer()) + validatePlanEmployeeAssignmentAndJurisdiction(request); + } + + /** + * Validates campaign ID from request against project factory + * + * @param campaignResponse The campaign details response from project factory + */ + private void validateCampaignId(CampaignResponse campaignResponse) { + if (CollectionUtils.isEmpty(campaignResponse.getCampaignDetails())) { + throw new CustomException(NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE, NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE); + } } /** * This validation method validates if the dependent activities are valid and if they form a cycle + * * @param request */ private void validateActivityDependencies(PlanRequest request) { @@ -90,6 +138,7 @@ private void validateActivityDependencies(PlanRequest request) { /** * This method checks if the activity dependencies form a cycle + * * @param request */ private void checkForCycleInActivityDependencies(PlanRequest request) { @@ -99,14 +148,15 @@ private void checkForCycleInActivityDependencies(PlanRequest request) { activityCodeVsDependenciesMap.keySet().forEach(activityCode -> { activityCodeVsDependenciesMap.get(activityCode).forEach(dependency -> { - if(activityCodeVsDependenciesMap.get(dependency).contains(activityCode)) - throw new CustomException("CYCLIC_ACTIVITY_DEPENDENCY", "Cyclic activity dependency found"); + if (activityCodeVsDependenciesMap.get(dependency).contains(activityCode)) + throw new CustomException(CYCLIC_ACTIVITY_DEPENDENCY_CODE, CYCLIC_ACTIVITY_DEPENDENCY_MESSAGE); }); }); } /** * This method validates if the dependent activity codes are valid + * * @param request */ private void validateDependentActivityCodes(PlanRequest request) { @@ -117,10 +167,10 @@ private void validateDependentActivityCodes(PlanRequest request) { // Check if the dependent activity codes are valid request.getPlan().getActivities().forEach(activity -> { - if(!CollectionUtils.isEmpty(activity.getDependencies())) { + if (!CollectionUtils.isEmpty(activity.getDependencies())) { activity.getDependencies().forEach(dependency -> { - if(!activityCodes.contains(dependency)) - throw new CustomException("INVALID_ACTIVITY_DEPENDENCY", "Activity dependency is invalid"); + if (!activityCodes.contains(dependency)) + throw new CustomException(INVALID_ACTIVITY_DEPENDENCY_CODE, INVALID_ACTIVITY_DEPENDENCY_MESSAGE); }); } }); @@ -129,88 +179,77 @@ private void validateDependentActivityCodes(PlanRequest request) { /** * This method validates the activities provided in the request + * * @param request */ private void validateActivities(PlanRequest request) { // Collect all activity codes - if(request.getPlan().getActivities() == null) - throw new CustomException("ACTIVITIES_CANNOT_BE_NULL","Activities list in Plan cannot be null"); + if (request.getPlan().getActivities() == null) + throw new CustomException(ACTIVITIES_CANNOT_BE_NULL_CODE, ACTIVITIES_CANNOT_BE_NULL_MESSAGE); Set activityCodes = request.getPlan().getActivities().stream() .map(Activity::getCode) .collect(Collectors.toSet()); // If activity codes are not unique, throw an exception - if(activityCodes.size() != request.getPlan().getActivities().size()) { - throw new CustomException("DUPLICATE_ACTIVITY_CODES", "Activity codes within the plan should be unique"); + if (activityCodes.size() != request.getPlan().getActivities().size()) { + throw new CustomException(DUPLICATE_ACTIVITY_CODES, DUPLICATE_ACTIVITY_CODES_MESSAGE); } // If execution plan id is not provided, providing activities is mandatory - if(ObjectUtils.isEmpty(request.getPlan().getExecutionPlanId()) + if (ObjectUtils.isEmpty(request.getPlan().getCampaignId()) && CollectionUtils.isEmpty(request.getPlan().getActivities())) { - throw new CustomException("PLAN_ACTIVITIES_MANDATORY", "Activities are mandatory if execution plan id is not provided"); + throw new CustomException(PLAN_ACTIVITIES_MANDATORY_CODE, PLAN_ACTIVITIES_MANDATORY_MESSAGE); } // If execution plan id is provided, providing activities is not allowed - if(!ObjectUtils.isEmpty(request.getPlan().getExecutionPlanId()) + if (!ObjectUtils.isEmpty(request.getPlan().getCampaignId()) && !CollectionUtils.isEmpty(request.getPlan().getActivities())) { - throw new CustomException("PLAN_ACTIVITIES_NOT_ALLOWED", "Activities are not allowed if execution plan id is provided"); + throw new CustomException(PLAN_ACTIVITIES_NOT_ALLOWED_CODE, PLAN_ACTIVITIES_NOT_ALLOWED_MESSAGE); } // Validate activity dates - if(!CollectionUtils.isEmpty(request.getPlan().getActivities())) { + if (!CollectionUtils.isEmpty(request.getPlan().getActivities())) { request.getPlan().getActivities().forEach(activity -> { - if(activity.getPlannedEndDate() < activity.getPlannedStartDate()) - throw new CustomException("INVALID_ACTIVITY_DATES", "Planned end date cannot be before planned start date"); + if (activity.getPlannedEndDate() < activity.getPlannedStartDate()) + throw new CustomException(INVALID_ACTIVITY_DATES_CODE, INVALID_ACTIVITY_DATES_MESSAGE); }); } } /** * This method validates if the plan configuration id provided in the request exists + * * @param request */ private void validatePlanConfigurationExistence(PlanRequest request) { // If plan id provided is invalid, throw an exception - if(!ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) && CollectionUtils.isEmpty(planConfigurationRepository.search(PlanConfigurationSearchCriteria.builder() - .id(request.getPlan().getPlanConfigurationId()) - .tenantId(request.getPlan().getTenantId()) - .build()))) { + if (!ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) && + CollectionUtils.isEmpty(commonUtil.searchPlanConfigId(request.getPlan().getPlanConfigurationId(), request.getPlan().getTenantId()))) { throw new CustomException(INVALID_PLAN_CONFIG_ID_CODE, INVALID_PLAN_CONFIG_ID_MESSAGE); } } /** * This method validates the resources provided in the request + * * @param request */ private void validateResources(PlanRequest request) { // If plan configuration id is not provided, providing resources is mandatory - if(ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) + if (ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) && CollectionUtils.isEmpty(request.getPlan().getResources())) { - throw new CustomException("PLAN_RESOURCES_MANDATORY", "Resources are mandatory if plan configuration id is not provided"); - } - - // If plan configuration id is provided, providing resources is not allowed - if(!ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) - && !CollectionUtils.isEmpty(request.getPlan().getResources())) { - throw new CustomException("PLAN_RESOURCES_NOT_ALLOWED", "Resources are not allowed if plan configuration id is provided"); - } - - // Validate resource type existence - if(!CollectionUtils.isEmpty(request.getPlan().getResources())) { - request.getPlan().getResources().forEach(resource -> { - // Validate resource type existence - }); + throw new CustomException(PLAN_RESOURCES_MANDATORY_CODE, PLAN_RESOURCES_MANDATORY_MESSAGE); } } /** * This method validates the linkage between resources and activities + * * @param request */ private void validateResourceActivityLinkage(PlanRequest request) { - if(ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) + if (ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) && !CollectionUtils.isEmpty(request.getPlan().getActivities())) { // Collect all activity codes Set activityCodes = request.getPlan().getActivities().stream() @@ -219,18 +258,19 @@ private void validateResourceActivityLinkage(PlanRequest request) { // Validate resource-activity linkage request.getPlan().getResources().forEach(resource -> { - if(!activityCodes.contains(resource.getActivityCode())) - throw new CustomException("INVALID_RESOURCE_ACTIVITY_LINKAGE", "Resource-Activity linkage is invalid"); + if (!activityCodes.contains(resource.getActivityCode())) + throw new CustomException(INVALID_RESOURCE_ACTIVITY_LINKAGE_CODE, INVALID_RESOURCE_ACTIVITY_LINKAGE_MESSAGE); }); } } /** * This method validates the linkage between targets and activities + * * @param request */ private void validateTargetActivityLinkage(PlanRequest request) { - if(!CollectionUtils.isEmpty(request.getPlan().getActivities())) { + if (!CollectionUtils.isEmpty(request.getPlan().getActivities())) { // Collect all activity codes Set activityCodes = request.getPlan().getActivities().stream() .map(Activity::getCode) @@ -238,22 +278,29 @@ private void validateTargetActivityLinkage(PlanRequest request) { // Validate target-activity linkage request.getPlan().getTargets().forEach(target -> { - if(!activityCodes.contains(target.getActivityCode())) - throw new CustomException("INVALID_TARGET_ACTIVITY_LINKAGE", "Target-Activity linkage is invalid"); + if (!activityCodes.contains(target.getActivityCode())) + throw new CustomException(INVALID_TARGET_ACTIVITY_LINKAGE_CODE, INVALID_TARGET_ACTIVITY_LINKAGE_MESSAGE); }); } } /** * This method performs business validations on plan update requests + * * @param request */ public void validatePlanUpdate(PlanRequest request) { // Validate plan existence validatePlanExistence(request); - String rootTenantId = request.getPlan().getTenantId().split("\\.")[0]; + String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlan().getTenantId()); Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(request.getRequestInfo(), request.getPlan().getCampaignId(), rootTenantId); + BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(request.getRequestInfo(), request.getPlan().getTenantId(), campaignResponse.getCampaignDetails().get(0).getHierarchyType()); + + //TODO: remove after setting the flag in consumer + request.getPlan().setRequestFromResourceEstimationConsumer(Boolean.TRUE); + // Validate activities validateActivities(request); @@ -288,57 +335,99 @@ public void validatePlanUpdate(PlanRequest request) { // Validate Metric Detail's Unit against MDMS validateMetricDetailUnit(request, mdmsData); + // Validate the user information in the request + commonUtil.validateUserInfo(request.getRequestInfo()); + + // Validate plan-employee assignment and jurisdiction + validatePlanEmployeeAssignmentAndJurisdiction(request); + + // Enrich jurisdiction mapping in plan + planEnricher.enrichJurisdictionMapping(request.getPlan(), boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0)); } + /** + * Validates that all target UUIDs within the provided PlanRequest are unique. + * + * @param request the PlanRequest containing the targets to be validated + * @throws CustomException if any target UUIDs are not unique + */ private void validateTargetUuidUniqueness(PlanRequest request) { - // Collect all target uuids + // Collect all target UUIDs Set targetUuids = request.getPlan().getTargets().stream() .map(Target::getId) .collect(Collectors.toSet()); - // If target uuids are not unique, throw an exception - if(targetUuids.size() != request.getPlan().getTargets().size()) { - throw new CustomException("DUPLICATE_TARGET_UUIDS", "Target uuids should be unique"); + // If target UUIDs are not unique, throw an exception + if (targetUuids.size() != request.getPlan().getTargets().size()) { + throw new CustomException(DUPLICATE_TARGET_UUIDS_CODE, DUPLICATE_TARGET_UUIDS_MESSAGE); } } + /** + * Validates that all resource UUIDs within the provided PlanRequest are unique. + * + * @param request the PlanRequest containing the resources to be validated + * @throws CustomException if any resource UUIDs are not unique + */ private void validateResourceUuidUniqueness(PlanRequest request) { - // Collect all resource uuids + // Collect all resource UUIDs Set resourceUuids = request.getPlan().getResources().stream() .map(Resource::getId) .collect(Collectors.toSet()); - // If resource uuids are not unique, throw an exception - if(resourceUuids.size() != request.getPlan().getResources().size()) { - throw new CustomException("DUPLICATE_RESOURCE_UUIDS", "Resource uuids should be unique"); + // If resource UUIDs are not unique, throw an exception + if (resourceUuids.size() != request.getPlan().getResources().size()) { + throw new CustomException(DUPLICATE_RESOURCE_UUIDS_CODE, DUPLICATE_RESOURCE_UUIDS_MESSAGE); } } + /** + * Validates that all activity UUIDs within the provided PlanRequest are unique. + * + * @param request the PlanRequest containing the activities to be validated + * @throws CustomException if any activity UUIDs are not unique + */ private void validateActivitiesUuidUniqueness(PlanRequest request) { - // Collect all activity uuids + // Collect all activity UUIDs Set activityUuids = request.getPlan().getActivities().stream() .map(Activity::getId) .collect(Collectors.toSet()); - // If activity uuids are not unique, throw an exception - if(activityUuids.size() != request.getPlan().getActivities().size()) { - throw new CustomException("DUPLICATE_ACTIVITY_UUIDS", "Activity uuids should be unique"); + // If activity UUIDs are not unique, throw an exception + if (activityUuids.size() != request.getPlan().getActivities().size()) { + throw new CustomException(DUPLICATE_ACTIVITY_UUIDS_CODE, DUPLICATE_ACTIVITY_UUIDS_MESSAGE); } } + /** * This method validates if the plan id provided in the update request exists - * @param request + * + * @param request the PlanRequest containing the plan */ private void validatePlanExistence(PlanRequest request) { // If plan id provided is invalid, throw an exception - if(CollectionUtils.isEmpty(planRepository.search(PlanSearchCriteria.builder() + List planFromDatabase = planRepository.search(PlanSearchCriteria.builder() .ids(Collections.singleton(request.getPlan().getId())) - .build()))) { - throw new CustomException("INVALID_PLAN_ID", "Plan id provided is invalid"); + .build()); + if (CollectionUtils.isEmpty(planFromDatabase)) { + throw new CustomException(INVALID_PLAN_ID_CODE, INVALID_PLAN_ID_MESSAGE); } + // enriching boundary ancestral path for incoming plan request from the database + request.getPlan().setBoundaryAncestralPath(planFromDatabase.get(0).getBoundaryAncestralPath()); } + /** + * Validates the target metrics within the provided PlanRequest against MDMS data. + * + * This method checks each target metric in the plan to ensure it exists in the MDMS data. + * If a metric is not found, it throws a CustomException. + * + * @param request the PlanRequest containing the plan and target metrics to be validated + * @param mdmsData the MDMS data against which the target metrics are validated + * @throws CustomException if there is an error reading the MDMS data using JsonPath + * or if any target metric is not found in the MDMS data + */ public void validateTargetMetrics(PlanRequest request, Object mdmsData) { Plan plan = request.getPlan(); final String jsonPathForMetric = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_METRIC + ".*.code"; @@ -350,14 +439,26 @@ public void validateTargetMetrics(PlanRequest request, Object mdmsData) { } catch (Exception e) { throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); } - - for (Target target : plan.getTargets()) { - if (!metricListFromMDMS.contains(target.getMetric())) { + HashSet metricSetFromMDMS = new HashSet<>(metricListFromMDMS); + plan.getTargets().stream().forEach(target -> { + if (!metricSetFromMDMS.contains(target.getMetric())) { throw new CustomException(METRIC_NOT_FOUND_IN_MDMS_CODE, METRIC_NOT_FOUND_IN_MDMS_MESSAGE); } - } + }); + } + /** + * Validates the metric unit details within the provided PlanRequest against MDMS data. + * + * This method extracts metric details from the plan and checks if each metric unit + * is present in the MDMS data. If a metric unit is not found, it throws a CustomException. + * + * @param request the PlanRequest containing the plan and metric details to be validated + * @param mdmsData the MDMS data against which the metric units are validated + * @throws CustomException if there is an error reading the MDMS data using JsonPath + * or if any metric unit is not found in the MDMS data + */ public void validateMetricDetailUnit(PlanRequest request, Object mdmsData) { Plan plan = request.getPlan(); @@ -365,19 +466,209 @@ public void validateMetricDetailUnit(PlanRequest request, Object mdmsData) { .map(Target::getMetricDetail) .toList(); - List metricUnitListFromMDMS = null; - final String jsonPathForMetricUnit = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_UOM + ".*.code"; + List metricUnitListFromMDMS; + final String jsonPathForMetricUnit = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_UOM + ".*.uomCode"; try { metricUnitListFromMDMS = JsonPath.read(mdmsData, jsonPathForMetricUnit); } catch (Exception e) { throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); } - for (MetricDetail metricDetail : metricDetails) { - if (!metricUnitListFromMDMS.contains(metricDetail.getMetricUnit())) { + HashSet metricUnitSetFromMDMS = new HashSet<>(metricUnitListFromMDMS); + metricDetails.stream().forEach(metricDetail -> { + if (!metricUnitSetFromMDMS.contains(metricDetail.getMetricUnit())) { throw new CustomException(METRIC_UNIT_NOT_FOUND_IN_MDMS_CODE, METRIC_UNIT_NOT_FOUND_IN_MDMS_MESSAGE); } + }); + + } + + /** + * Validates the plan's employee assignment and ensures the jurisdiction is valid based on tenant, employee, role, and plan configuration. + * If no assignment is found, throws a custom exception. + * + * @param planRequest the request containing the plan and workflow details + * @throws CustomException if no employee assignment is found or jurisdiction is invalid + */ + public void validatePlanEmployeeAssignmentAndJurisdiction(PlanRequest planRequest) { + PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = PlanEmployeeAssignmentSearchCriteria + .builder() + .tenantId(planRequest.getPlan().getTenantId()) + .employeeId(Collections.singletonList(planRequest.getRequestInfo().getUserInfo().getUuid())) + .planConfigurationId(planRequest.getPlan().getPlanConfigurationId()) + .role(config.getPlanEstimationApproverRoles()) + .build(); + + PlanEmployeeAssignmentResponse planEmployeeAssignmentResponse = planEmployeeService.search(PlanEmployeeAssignmentSearchRequest.builder() + .planEmployeeAssignmentSearchCriteria(planEmployeeAssignmentSearchCriteria) + .requestInfo(planRequest.getRequestInfo()).build()); + + if(CollectionUtils.isEmpty(planEmployeeAssignmentResponse.getPlanEmployeeAssignment())) + throw new CustomException(PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_CODE, PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_MESSAGE + planRequest.getPlan().getLocality()); + + validateJurisdiction(planRequest.getPlan(), + planEmployeeAssignmentResponse.getPlanEmployeeAssignment().get(0).getJurisdiction()); + } + + /** + * Validates that at least one jurisdiction exists within the hierarchy's boundary codes. + * If no jurisdiction is found in the boundary set, throws a custom exception. + * + * @param plan the plan containing the boundary ancestral path + * @param jurisdictions the list of jurisdictions to check against the boundary set + * @throws CustomException if none of the jurisdictions are present in the boundary codes + */ + public void validateJurisdiction(Plan plan, Set jurisdictions) { + Set boundarySet = new HashSet<>(Arrays.asList(plan.getBoundaryAncestralPath() + .split(PIPE_REGEX))); + + // Check if any jurisdiction is present in the boundary set + if (jurisdictions.stream().noneMatch(boundarySet::contains)) + throw new CustomException(JURISDICTION_NOT_FOUND_CODE, JURISDICTION_NOT_FOUND_MESSAGE); + + // Enrich jurisdiction of current assignee + plan.setAssigneeJurisdiction(new ArrayList<>(jurisdictions)); + + } + + /** + * Validates the boundary code provided in plan request against boundary service. + * + * @param boundarySearchResponse response from the boundary service. + * @param plan Plan record whose loclality is to be validated. + */ + private void validateBoundaryCode(BoundarySearchResponse boundarySearchResponse, Plan plan) { + HierarchyRelation tenantBoundary = boundarySearchResponse.getTenantBoundary().get(0); + + if (CollectionUtils.isEmpty(tenantBoundary.getBoundary())) { + throw new CustomException(NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE, NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE); + } + + // Enrich the boundary ancestral path and jurisdiction mapping for the provided boundary code + if(plan.isRequestFromResourceEstimationConsumer()) + planEnricher.enrichBoundaryAncestralPath(plan, tenantBoundary); + } + + /** + * @param bulkPlanRequest + */ + public void validateBulkPlanUpdate(BulkPlanRequest bulkPlanRequest) { + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(bulkPlanRequest.getRequestInfo(), bulkPlanRequest.getPlans().get(0).getCampaignId(), bulkPlanRequest.getPlans().get(0).getTenantId()); + BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(bulkPlanRequest.getRequestInfo(), bulkPlanRequest.getPlans().get(0).getTenantId(), campaignResponse.getCampaignDetails().get(0).getHierarchyType()); + + // Validate attributes across each plan in the bulk request + validatePlanAttributes(bulkPlanRequest); + + // Validate if plans provided in the request body exist + validatePlanExistence(bulkPlanRequest); + + // Validate plan employee assignment and jurisdiction + validatePlanEmployeeAssignmentAndJurisdiction(bulkPlanRequest); + + // Enrich jurisdiction mapping in plan + planEnricher.enrichJurisdictionMapping(bulkPlanRequest.getPlans(), boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0)); + } + + /** + * + * @param bulkPlanRequest + */ + private void validatePlanEmployeeAssignmentAndJurisdiction(BulkPlanRequest bulkPlanRequest) { + // Prepare plan employee assignment search criteria + PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = PlanEmployeeAssignmentSearchCriteria + .builder() + .tenantId(bulkPlanRequest.getPlans().get(0).getTenantId()) + .employeeId(Collections.singletonList(bulkPlanRequest.getRequestInfo().getUserInfo().getUuid())) + .planConfigurationId(bulkPlanRequest.getPlans().get(0).getPlanConfigurationId()) + .role(config.getPlanEstimationApproverRoles()) + .build(); + + // Fetch plan employee assignment + PlanEmployeeAssignmentResponse planEmployeeAssignmentResponse = planEmployeeService.search(PlanEmployeeAssignmentSearchRequest.builder() + .planEmployeeAssignmentSearchCriteria(planEmployeeAssignmentSearchCriteria) + .requestInfo(bulkPlanRequest.getRequestInfo()) + .build()); + + // Throw exception if the employee taking action is not a part of plan + if(CollectionUtils.isEmpty(planEmployeeAssignmentResponse.getPlanEmployeeAssignment())) { + throw new CustomException(PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_CODE, + PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_MESSAGE); + } + + // Validate jurisdiction for each plan + bulkPlanRequest.getPlans().forEach(plan -> validateJurisdiction(plan, + planEmployeeAssignmentResponse.getPlanEmployeeAssignment().get(0).getJurisdiction())); + + } + + /** + * + * @param bulkPlanRequest + */ + private void validatePlanAttributes(BulkPlanRequest bulkPlanRequest) { + if(bulkPlanRequest.getPlans().stream().map(Plan :: getId).collect(Collectors.toSet()).size() + != bulkPlanRequest.getPlans().size()) { + throw new CustomException("BULK_UPDATE_ERROR", + "Plans provided in the bulk update request are not unique."); + } + + if(!bulkPlanRequest.getPlans().stream().allMatch(plan -> + plan.getTenantId().equals(bulkPlanRequest.getPlans().get(0).getTenantId()) && + plan.getPlanConfigurationId().equals(bulkPlanRequest.getPlans().get(0).getPlanConfigurationId()))) { + throw new CustomException("BULK_UPDATE_ERROR", + "Tenant id and plan configuration ids should be same across all entries for bulk update."); + } + + bulkPlanRequest.getPlans().forEach(plan -> { + if(ObjectUtils.isEmpty(plan.getWorkflow())) { + throw new CustomException("BULK_UPDATE_ERROR", + "Workflow information is mandatory for each entry for bulk update"); + } + }); + + if(!bulkPlanRequest.getPlans().stream().allMatch(plan -> + plan.getStatus().equals(bulkPlanRequest.getPlans().get(0).getStatus()) && + plan.getWorkflow().getAction().equals(bulkPlanRequest.getPlans().get(0).getWorkflow().getAction()))) { + throw new CustomException("BULK_UPDATE_ERROR", + "All entries should be in the same state for bulk transitioning plan records."); } + } + /** + * + * @param bulkPlanRequest + */ + private void validatePlanExistence(BulkPlanRequest bulkPlanRequest) { + // Get all plan ids to validate existence + List planListFromDatabase = planRepository.search(PlanSearchCriteria.builder() + .ids(bulkPlanRequest.getPlans().stream().map(Plan :: getId).collect(Collectors.toSet())) + .offset(0) + .limit(bulkPlanRequest.getPlans().size()) + .build()); + + // If plan id provided is invalid, throw an exception + if (planListFromDatabase.size() != bulkPlanRequest.getPlans().size()) { + throw new CustomException(INVALID_PLAN_ID_CODE, INVALID_PLAN_ID_MESSAGE); + } + + // Enrich ancestral materialized path for each plan object being passed in the request + enrichAncestralMaterializedPath(bulkPlanRequest, planListFromDatabase); + + } + + /** + * + * @param bulkPlanRequest + * @param planListFromDatabase + */ + private void enrichAncestralMaterializedPath(BulkPlanRequest bulkPlanRequest, List planListFromDatabase) { + Map planIdVsAncestralMaterializedPathMap = planListFromDatabase.stream() + .collect(Collectors.toMap(Plan :: getId, Plan :: getBoundaryAncestralPath)); + + bulkPlanRequest.getPlans().forEach(plan -> + plan.setBoundaryAncestralPath(planIdVsAncestralMaterializedPathMap + .get(plan.getId())) + ); + } } diff --git a/health-services/plan-service/src/main/java/digit/service/enrichment/EnrichmentService.java b/health-services/plan-service/src/main/java/digit/service/enrichment/EnrichmentService.java index 787e5ce2766..7dfb66f4a64 100644 --- a/health-services/plan-service/src/main/java/digit/service/enrichment/EnrichmentService.java +++ b/health-services/plan-service/src/main/java/digit/service/enrichment/EnrichmentService.java @@ -1,148 +1,144 @@ package digit.service.enrichment; import digit.config.Configuration; -import digit.web.models.File; -import digit.web.models.PlanConfiguration; -import digit.web.models.PlanConfigurationRequest; -import digit.web.models.ResourceMapping; +import digit.util.CommonUtil; +import digit.web.models.*; import lombok.extern.slf4j.Slf4j; -import org.egov.common.utils.AuditDetailsEnrichmentUtil; import org.egov.common.utils.UUIDEnrichmentUtil; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; import java.util.List; -import static digit.config.ServiceConstants.USERINFO_MISSING_CODE; -import static digit.config.ServiceConstants.USERINFO_MISSING_MESSAGE; -import org.springframework.util.ObjectUtils; + +import static digit.config.ServiceConstants.DRAFT_STATUS; +import static org.egov.common.utils.AuditDetailsEnrichmentUtil.prepareAuditDetails; @Component @Slf4j public class EnrichmentService { private Configuration config; - public EnrichmentService(Configuration config) { + private CommonUtil commonUtil; + + public EnrichmentService(Configuration config, CommonUtil commonUtil) { this.config = config; + this.commonUtil = commonUtil; } /** * Enriches the PlanConfigurationRequest for creating a new plan configuration. - * This method enriches the plan configuration with generated IDs, validates user information, and enriches audit details for create operation. + * Enriches the given plan configuration with generated IDs for plan, files, assumptions, operations, and resource mappings, + * validates user information, and enriches audit details for create operation. + * * @param request The PlanConfigurationRequest to be enriched. * @throws CustomException if user information is missing in the request. */ public void enrichCreate(PlanConfigurationRequest request) { - enrichPlanConfiguration(request.getPlanConfiguration()); - if(ObjectUtils.isEmpty(request.getRequestInfo().getUserInfo())) - throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); - - enrichAuditDetails(request, Boolean.TRUE); - } - - /** - * Enriches the given plan configuration with generated IDs for plan, files, assumptions, operations, and resource mappings. - * @param planConfiguration The PlanConfiguration to be enriched. - */ - public void enrichPlanConfiguration(PlanConfiguration planConfiguration) { + PlanConfiguration planConfiguration = request.getPlanConfiguration(); log.info("Enriching plan config with generated IDs"); + //set Draft status on create + planConfiguration.setStatus(DRAFT_STATUS); + // Generate id for plan configuration UUIDEnrichmentUtil.enrichRandomUuid(planConfiguration, "id"); // Generate id for files - planConfiguration.getFiles().forEach(file -> { - UUIDEnrichmentUtil.enrichRandomUuid(file, "id"); - enrichActiveForResourceMapping(file, planConfiguration.getResourceMapping()); - }); - + if (!CollectionUtils.isEmpty(planConfiguration.getFiles())) { + planConfiguration.getFiles().forEach(file -> { + UUIDEnrichmentUtil.enrichRandomUuid(file, "id"); + enrichActiveForResourceMapping(file, planConfiguration.getResourceMapping()); + }); + } // Generate id for assumptions - planConfiguration.getAssumptions().forEach(assumption -> UUIDEnrichmentUtil.enrichRandomUuid(assumption, "id")); + if (!CollectionUtils.isEmpty(planConfiguration.getAssumptions())) { + planConfiguration.getAssumptions().forEach(assumption -> UUIDEnrichmentUtil.enrichRandomUuid(assumption, "id")); + } + // Generate id for operations - planConfiguration.getOperations().forEach(operation -> UUIDEnrichmentUtil.enrichRandomUuid(operation, "id")); + if (!CollectionUtils.isEmpty(planConfiguration.getOperations())) { + planConfiguration.getOperations().forEach(operation -> UUIDEnrichmentUtil.enrichRandomUuid(operation, "id")); + } // Generate id for resource mappings - planConfiguration.getResourceMapping().forEach(resourceMapping -> UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id")); - } + if (!CollectionUtils.isEmpty(planConfiguration.getResourceMapping())) { + planConfiguration.getResourceMapping().forEach(resourceMapping -> UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id")); + } - /** - * Enriches the audit details for the PlanConfigurationRequest based on the operation type (create or update). - * @param request The PlanConfigurationRequest for which audit details are to be enriched. - * @param isCreate A boolean indicating whether the operation is a create or update operation. - */ - public void enrichAuditDetails(PlanConfigurationRequest request, Boolean isCreate) { - PlanConfiguration planConfiguration = request.getPlanConfiguration(); - planConfiguration.setAuditDetails(AuditDetailsEnrichmentUtil - .prepareAuditDetails(planConfiguration.getAuditDetails(), request.getRequestInfo(), isCreate)); + planConfiguration.setAuditDetails(prepareAuditDetails(planConfiguration.getAuditDetails(), request.getRequestInfo(), Boolean.TRUE)); } /** * Enriches the PlanConfigurationRequest for updating an existing plan configuration. * This method enriches the plan configuration for update, validates user information, and enriches audit details for update operation. + * * @param request The PlanConfigurationRequest to be enriched. * @throws CustomException if user information is missing in the request. */ public void enrichUpdate(PlanConfigurationRequest request) { - enrichPlanConfigurationForUpdate(request); - if (request.getRequestInfo().getUserInfo() == null) - throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); + PlanConfiguration planConfiguration = request.getPlanConfiguration(); - enrichAuditDetails(request, Boolean.FALSE); - } + // Generate id for Files + if (!CollectionUtils.isEmpty(planConfiguration.getFiles())) { + planConfiguration.getFiles().forEach(file -> { + if (ObjectUtils.isEmpty(file.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(file, "id"); + } + enrichActiveForResourceMapping(file, request.getPlanConfiguration().getResourceMapping()); + }); + } - /** - * Enriches the plan configuration for update by generating IDs for files, assumptions, operations, and resource mappings if they are empty. - * @param request The PlanConfigurationRequest to be enriched for update operation. - */ - public void enrichPlanConfigurationForUpdate(PlanConfigurationRequest request) { - PlanConfiguration planConfiguration = request.getPlanConfiguration(); + // Generate id for Assumptions + if (!CollectionUtils.isEmpty(planConfiguration.getAssumptions())) { + planConfiguration.getAssumptions().forEach(assumption -> { + if (ObjectUtils.isEmpty(assumption.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(assumption, "id"); + } + }); + } - // For Files - planConfiguration.getFiles().forEach(file -> { - if (ObjectUtils.isEmpty(file.getId())) { - UUIDEnrichmentUtil.enrichRandomUuid(file, "id"); - } - enrichActiveForResourceMapping(file, request.getPlanConfiguration().getResourceMapping()); - }); - - // For Assumptions - planConfiguration.getAssumptions().forEach(assumption -> { - if (ObjectUtils.isEmpty(assumption.getId())) { - UUIDEnrichmentUtil.enrichRandomUuid(assumption, "id"); - } - }); - - // For Operations - planConfiguration.getOperations().forEach(operation -> { - if (ObjectUtils.isEmpty(operation.getId())) { - UUIDEnrichmentUtil.enrichRandomUuid(operation, "id"); - } - }); - - // For ResourceMappings - planConfiguration.getResourceMapping().forEach(resourceMapping -> { - if (ObjectUtils.isEmpty(resourceMapping.getId())) { - UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id"); - } - }); + // Generate id for Operations + if (!CollectionUtils.isEmpty(planConfiguration.getOperations())) { + planConfiguration.getOperations().forEach(operation -> { + if (ObjectUtils.isEmpty(operation.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(operation, "id"); + } + }); + } + // Generate id for ResourceMappings + if (!CollectionUtils.isEmpty(planConfiguration.getResourceMapping())) { + planConfiguration.getResourceMapping().forEach(resourceMapping -> { + if (ObjectUtils.isEmpty(resourceMapping.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id"); + } + }); + } + + planConfiguration.setAuditDetails(prepareAuditDetails(request.getPlanConfiguration().getAuditDetails(), request.getRequestInfo(), Boolean.FALSE)); + + //enrich execution order for operations on setup complete + if (commonUtil.checkForEmptyOperationsOrAssumptions(planConfiguration)) { + enrichExecutionOrderForOperations(planConfiguration); + } } /** * Sets all corresponding resource mappings to inactive if the given file is inactive. * - * @param file the file object which may be inactive + * @param file the file object which may be inactive * @param resourceMappings the list of resource mappings to update */ public void enrichActiveForResourceMapping(File file, List resourceMappings) { if (!file.getActive()) { // Set all corresponding resource mappings to inactive - for (ResourceMapping mapping : resourceMappings) { - if (mapping.getFilestoreId().equals(file.getFilestoreId())) { - mapping.setActive(false); - } - } + resourceMappings.stream() + .filter(mapping -> mapping.getFilestoreId().equals(file.getFilestoreId())) + .forEach(mapping -> mapping.setActive(false)); } } @@ -153,34 +149,55 @@ public void enrichActiveForResourceMapping(File file, List reso * * @param request the plan configuration request containing the plan configuration to be enriched */ - public void enrichPlanConfigurationBeforeValidation(PlanConfigurationRequest request) - { + public void enrichPlanConfigurationBeforeValidation(PlanConfigurationRequest request) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); // For Files, Operations, Assumptions and Resource Mappings override active to be True - planConfiguration.getFiles().forEach(file -> { - if (ObjectUtils.isEmpty(file.getId())) { - file.setActive(Boolean.TRUE); - } - }); - - planConfiguration.getOperations().forEach(operation -> { - if (ObjectUtils.isEmpty(operation.getId())) { - operation.setActive(Boolean.TRUE); - } - }); - - planConfiguration.getAssumptions().forEach(assumption -> { - if (ObjectUtils.isEmpty(assumption.getId())) { - assumption.setActive(Boolean.TRUE); - } - }); - - planConfiguration.getResourceMapping().forEach(resourceMapping -> { - if (ObjectUtils.isEmpty(resourceMapping.getId())) { - resourceMapping.setActive(Boolean.TRUE); - } - }); + if (!CollectionUtils.isEmpty(planConfiguration.getFiles())) { + planConfiguration.getFiles().forEach(file -> { + if (ObjectUtils.isEmpty(file.getId())) { + file.setActive(Boolean.TRUE); + } + }); + } + + if (!CollectionUtils.isEmpty(planConfiguration.getOperations())) { + planConfiguration.getOperations().forEach(operation -> { + if (ObjectUtils.isEmpty(operation.getId())) { + operation.setActive(Boolean.TRUE); + } + }); + } + + if (!CollectionUtils.isEmpty(planConfiguration.getAssumptions())) { + planConfiguration.getAssumptions().forEach(assumption -> { + if (ObjectUtils.isEmpty(assumption.getId())) { + assumption.setActive(Boolean.TRUE); + } + }); + } + + if (!CollectionUtils.isEmpty(planConfiguration.getResourceMapping())) { + planConfiguration.getResourceMapping().forEach(resourceMapping -> { + if (ObjectUtils.isEmpty(resourceMapping.getId())) { + resourceMapping.setActive(Boolean.TRUE); + } + }); + } + } + + /** + * Sets a sequential execution order for each operation in the given PlanConfiguration. + * + * @param planConfiguration the configuration containing operations to order + */ + public void enrichExecutionOrderForOperations(PlanConfiguration planConfiguration) { + int executionOrderCounter = 1; + + for (Operation operation : planConfiguration.getOperations()) { + if(operation.getActive()) + operation.setExecutionOrder(executionOrderCounter++); + } } } diff --git a/health-services/plan-service/src/main/java/digit/service/enrichment/PlanEmployeeAssignmentEnricher.java b/health-services/plan-service/src/main/java/digit/service/enrichment/PlanEmployeeAssignmentEnricher.java new file mode 100644 index 00000000000..c4072ca637e --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/enrichment/PlanEmployeeAssignmentEnricher.java @@ -0,0 +1,71 @@ +package digit.service.enrichment; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import digit.repository.PlanEmployeeAssignmentRepository; +import digit.util.CommonUtil; +import digit.web.models.*; +import org.egov.common.utils.UUIDEnrichmentUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static digit.config.ServiceConstants.*; +import static org.egov.common.utils.AuditDetailsEnrichmentUtil.prepareAuditDetails; + +@Component +public class PlanEmployeeAssignmentEnricher { + + private ObjectMapper objectMapper; + + private PlanEmployeeAssignmentRepository repository; + + private CommonUtil commonUtil; + + public PlanEmployeeAssignmentEnricher(ObjectMapper objectMapper, CommonUtil commonUtil, PlanEmployeeAssignmentRepository repository) { + this.objectMapper = objectMapper; + this.commonUtil = commonUtil; + this.repository = repository; + } + + /** + * Enriches the PlanEmployeeAssignmentRequest with id and audit details and sets active as true. + * + * @param request The PlanEmployeeAssignmentRequest body to be enriched + */ + public void enrichCreate(PlanEmployeeAssignmentRequest request) { + PlanEmployeeAssignment planEmployeeAssignment = request.getPlanEmployeeAssignment(); + + // Generate id for Plan employee assignment body + UUIDEnrichmentUtil.enrichRandomUuid(planEmployeeAssignment, "id"); + + // Set active true + planEmployeeAssignment.setActive(Boolean.TRUE); + + // Set Audit Details for Plan employee assignment + planEmployeeAssignment.setAuditDetails(prepareAuditDetails(planEmployeeAssignment.getAuditDetails(), + request.getRequestInfo(), + Boolean.TRUE)); + + // Add plan config name to which the employee is mapped + planEmployeeAssignment.setPlanConfigurationName(commonUtil.getPlanConfigName(planEmployeeAssignment.getTenantId(), planEmployeeAssignment.getPlanConfigurationId())); + } + + /** + * Enriches the PlanEmployeeAssignmentRequest for updating an existing plan employee assignment with audit details. + * + * @param request The PlanEmployeeAssignmentRequest body to be enriched + */ + public void enrichUpdate(PlanEmployeeAssignmentRequest request) { + PlanEmployeeAssignment planEmployeeAssignment = request.getPlanEmployeeAssignment(); + + // Set Audit Details for Plan employee assignment update + planEmployeeAssignment.setAuditDetails(prepareAuditDetails(planEmployeeAssignment.getAuditDetails(), + request.getRequestInfo(), + Boolean.FALSE)); + } +} diff --git a/health-services/plan-service/src/main/java/digit/service/enrichment/PlanFacilityEnricher.java b/health-services/plan-service/src/main/java/digit/service/enrichment/PlanFacilityEnricher.java new file mode 100644 index 00000000000..a07530dbfd2 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/enrichment/PlanFacilityEnricher.java @@ -0,0 +1,213 @@ +package digit.service.enrichment; + +import digit.util.BoundaryUtil; +import digit.util.CensusUtil; +import digit.util.CommonUtil; +import digit.web.models.PlanFacility; +import digit.web.models.PlanFacilityRequest; +import digit.web.models.PlanFacilitySearchCriteria; +import digit.web.models.PlanFacilitySearchRequest; +import digit.web.models.boundary.BoundarySearchResponse; +import digit.web.models.boundary.EnrichedBoundary; +import digit.web.models.census.*; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.utils.AuditDetailsEnrichmentUtil; +import org.egov.common.utils.UUIDEnrichmentUtil; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.*; +import static org.egov.common.utils.AuditDetailsEnrichmentUtil.prepareAuditDetails; + +@Component +@Slf4j +public class PlanFacilityEnricher { + + private CommonUtil commonUtil; + + private CensusUtil censusUtil; + + private BoundaryUtil boundaryUtil; + + public PlanFacilityEnricher(CommonUtil commonUtil, CensusUtil censusUtil, BoundaryUtil boundaryUtil) { + this.commonUtil = commonUtil; + this.censusUtil = censusUtil; + this.boundaryUtil = boundaryUtil; + } + + /** + * Enriches the plan facility create request + * + * @param planFacilityRequest + */ + public void enrichPlanFacilityCreate(@Valid PlanFacilityRequest planFacilityRequest) { + // Generate id for plan facility + UUIDEnrichmentUtil.enrichRandomUuid(planFacilityRequest.getPlanFacility(), "id"); + + // Enrich audit details + planFacilityRequest.getPlanFacility().setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails(planFacilityRequest.getPlanFacility().getAuditDetails(), + planFacilityRequest.getRequestInfo(), Boolean.TRUE)); + + //Set Active + planFacilityRequest.getPlanFacility().setActive(Boolean.TRUE); + + // Add plan config name to which the facility is mapped + planFacilityRequest.getPlanFacility().setPlanConfigurationName(commonUtil.getPlanConfigName(planFacilityRequest.getPlanFacility().getTenantId(), planFacilityRequest.getPlanFacility().getPlanConfigurationId())); + } + + public void enrichJurisdictionMapping(PlanFacilityRequest request, String hierarchyType) { + BoundarySearchResponse boundarySearchResponse = boundaryUtil.fetchBoundaryData(request.getRequestInfo(), request.getPlanFacility().getResidingBoundary(), request.getPlanFacility().getTenantId(), hierarchyType, Boolean.TRUE, Boolean.FALSE); + + EnrichedBoundary boundary = boundarySearchResponse.getTenantBoundary().get(0).getBoundary().get(0); + Map jurisdictionMapping = new LinkedHashMap<>(); + + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + StringBuilder boundaryAncestralPath = new StringBuilder(boundary.getCode()); + + // Iterate through the child boundary until there are no more + while (!CollectionUtils.isEmpty(boundary.getChildren())) { + boundary = boundary.getChildren().get(0); + + boundaryAncestralPath.append("|").append(boundary.getCode()); + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + } + + // Setting the boundary ancestral path for the provided boundary + request.getPlanFacility().setBoundaryAncestralPath(boundaryAncestralPath.toString()); + + // Setting jurisdiction mapping for the provided boundary + request.getPlanFacility().setJurisdictionMapping(jurisdictionMapping); + } + + /** + * Enriches the plan facility update request + * + * @param planFacilityRequest The PlanFacilityRequest object contains the plan facility to be enriched. + */ + public void enrichPlanFacilityUpdate(PlanFacilityRequest planFacilityRequest) { + PlanFacility planFacility = planFacilityRequest.getPlanFacility(); + + //enrich audit details + planFacility.setAuditDetails(prepareAuditDetails(planFacilityRequest.getPlanFacility().getAuditDetails(), planFacilityRequest.getRequestInfo(), Boolean.FALSE)); + + // enrich serving population + enrichServingPopulation(planFacilityRequest); + } + + /** + * Enriches serving population based on the serving boundaries provided. + * + * @param planFacilityRequest plan facility request whose serving population is to be enriched. + */ + private void enrichServingPopulation(PlanFacilityRequest planFacilityRequest) { + PlanFacility planFacility = planFacilityRequest.getPlanFacility(); + + // Prepare list of boundaries whose census records are to be fetched + Set boundariesToBeSearched = new HashSet<>(planFacility.getServiceBoundaries()); + boundariesToBeSearched.addAll(planFacility.getInitiallySetServiceBoundaries()); + + if(!CollectionUtils.isEmpty(boundariesToBeSearched)) { + CensusSearchCriteria censusSearchCriteria = CensusSearchCriteria.builder() + .tenantId(planFacility.getTenantId()) + .source(planFacility.getPlanConfigurationId()) + .areaCodes(new ArrayList<>(boundariesToBeSearched)) + .limit(boundariesToBeSearched.size()) + .build(); + + CensusResponse censusResponse = censusUtil.fetchCensusRecords(CensusSearchRequest.builder() + .requestInfo(planFacilityRequest.getRequestInfo()) + .censusSearchCriteria(censusSearchCriteria) + .build()); + + // Creates a population map based on the confirmed target population of the boundary + Map boundaryToPopMap = getPopulationMap(censusResponse.getCensus()); + + // Get existing servingPopulation or default to 0 + BigDecimal servingPopulation = (BigDecimal) commonUtil.extractFieldsFromJsonObject(planFacility.getAdditionalDetails(), SERVING_POPULATION_CODE); + + updateServingPopulation(boundariesToBeSearched, planFacility, boundaryToPopMap, servingPopulation); + } + } + + /** + * Creates a mapping of boundary with it's confirmed target population. + * + * @param censusList Census records for the given list of serving boundaries. + * @return returns a map of boundary with its confirmed target population. + */ + private Map getPopulationMap(List censusList) { + Map boundaryToPopMap = new HashMap<>(); + + for (Census census : censusList) { + Map additionalFieldsMap = census.getAdditionalFields().stream() + .collect(Collectors.toMap(AdditionalField::getKey, AdditionalField::getValue)); + + Long confirmedTargetPopulation = 0L; + + // Get confirmed target population based on campaign type. + if (additionalFieldsMap.containsKey(CONFIRMED_TARGET_POPULATION_AGE_3TO11)) { + confirmedTargetPopulation = additionalFieldsMap.get(CONFIRMED_TARGET_POPULATION_AGE_3TO11) + .add(additionalFieldsMap.get(CONFIRMED_TARGET_POPULATION_AGE_12TO59)) + .longValue(); + } else if(additionalFieldsMap.containsKey(CONFIRMED_TARGET_POPULATION)){ + confirmedTargetPopulation = additionalFieldsMap.get(CONFIRMED_TARGET_POPULATION).longValue(); + } + + // Map the boundary code with it's confirmed target population. + boundaryToPopMap.put(census.getBoundaryCode(), confirmedTargetPopulation); + } + + return boundaryToPopMap; + } + + private void updateServingPopulation(Set boundariesToBeSearched, PlanFacility planFacility, Map boundaryToPopMap, BigDecimal servingPopulation) { + Set currentServiceBoundaries = new HashSet<>(planFacility.getServiceBoundaries()); + Set initialServiceBoundaries = new HashSet<>(planFacility.getInitiallySetServiceBoundaries()); + + for(String boundary : boundariesToBeSearched) { + Long totalPopulation = boundaryToPopMap.get(boundary); + + if (!currentServiceBoundaries.contains(boundary)) { + servingPopulation = servingPopulation.subtract(BigDecimal.valueOf(totalPopulation)); + } else if (!initialServiceBoundaries.contains(boundary)) { + servingPopulation = servingPopulation.add(BigDecimal.valueOf(totalPopulation)); + } + } + Map fieldToUpdate = new HashMap<>(); + fieldToUpdate.put(SERVING_POPULATION_CODE, servingPopulation); + + planFacility.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(planFacility.getAdditionalDetails(), fieldToUpdate)); + } + + /** + * Enriches plan facility search request + * + * @param planFacilitySearchRequest + */ + public void enrichSearchRequest(PlanFacilitySearchRequest planFacilitySearchRequest) { + PlanFacilitySearchCriteria planFacilitySearchCriteria = planFacilitySearchRequest.getPlanFacilitySearchCriteria(); + + // Filter map for filtering facility meta data present in additional details + Map filtersMap = new LinkedHashMap<>(); + + // Add facility status as a filter if present in search criteria + if(!ObjectUtils.isEmpty(planFacilitySearchCriteria.getFacilityStatus())) { + filtersMap.put(FACILITY_STATUS_SEARCH_PARAMETER_KEY, planFacilitySearchCriteria.getFacilityStatus()); + } + + // Add facility type as a filter if present in search criteria + if(!ObjectUtils.isEmpty(planFacilitySearchCriteria.getFacilityType())) { + filtersMap.put(FACILITY_TYPE_SEARCH_PARAMETER_KEY, planFacilitySearchCriteria.getFacilityType()); + } + + if(!CollectionUtils.isEmpty(filtersMap)) + planFacilitySearchCriteria.setFiltersMap(filtersMap); + } +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java b/health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java index 115c19855d8..58041c3324d 100644 --- a/health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java +++ b/health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java @@ -1,262 +1,281 @@ package digit.service.validator; +import com.fasterxml.jackson.databind.JsonNode; import com.jayway.jsonpath.JsonPath; -import digit.config.ServiceConstants; import digit.repository.PlanConfigurationRepository; +import digit.util.CampaignUtil; +import digit.util.CommonUtil; import digit.util.MdmsUtil; +import digit.util.MdmsV2Util; import digit.web.models.*; - -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - +import digit.web.models.mdmsV2.Mdms; +import digit.web.models.projectFactory.CampaignResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.egov.common.utils.MultiStateInstanceUtil; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import java.util.*; +import java.util.stream.Collectors; + import static digit.config.ServiceConstants.*; @Component @Slf4j public class PlanConfigurationValidator { - private MdmsUtil mdmsUtil; + private MdmsV2Util mdmsV2Util; + private PlanConfigurationRepository planConfigRepository; - public PlanConfigurationValidator(MdmsUtil mdmsUtil, PlanConfigurationRepository planConfigRepository) { + private CommonUtil commonUtil; + + private MultiStateInstanceUtil centralInstanceUtil; + + private CampaignUtil campaignUtil; + + public PlanConfigurationValidator(MdmsUtil mdmsUtil, MdmsV2Util mdmsV2Util, PlanConfigurationRepository planConfigRepository, CommonUtil commonUtil, MultiStateInstanceUtil centralInstanceUtil, CampaignUtil campaignUtil) { this.mdmsUtil = mdmsUtil; + this.mdmsV2Util = mdmsV2Util; this.planConfigRepository = planConfigRepository; + this.commonUtil = commonUtil; + this.centralInstanceUtil = centralInstanceUtil; + this.campaignUtil = campaignUtil; } /** * Validates the create request for plan configuration, including assumptions against MDMS data. + * * @param request The create request for plan configuration. */ public void validateCreate(PlanConfigurationRequest request) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); - String rootTenantId = planConfiguration.getTenantId().split("\\.")[0]; + String rootTenantId = centralInstanceUtil.getStateLevelTenant(planConfiguration.getTenantId()); Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + List mdmsV2Data = mdmsV2Util.fetchMdmsV2Data(request.getRequestInfo(), rootTenantId, MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_SCHEMA_VEHICLE_DETAILS, null); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(request.getRequestInfo(), request.getPlanConfiguration().getCampaignId(), rootTenantId); + + // Validate if the plan configuration for the provided name and campaign id already exists + validateDuplicateRecord(planConfiguration); + + // Validate if campaign id exists against project factory + validateCampaignId(campaignResponse); + // Validate that the assumption keys in the request are present in the MDMS data validateAssumptionKeyAgainstMDMS(request, mdmsData); - validateAssumptionValue(planConfiguration); - validateFilestoreId(planConfiguration); + + // Validate that the assumption keys in the request are unique + validateAssumptionUniqueness(planConfiguration); + + // Validate that the template identifiers in the request match those in the MDMS data validateTemplateIdentifierAgainstMDMS(request, mdmsData); - validateOperationsInputAgainstMDMS(request, mdmsData); - validateResourceMappingAgainstMDMS(request, mdmsData); - validateMappedToUniqueness(planConfiguration.getResourceMapping()); + + //Validating operation's input and assumptionValue fields + validateOperations(request, campaignResponse); + + //Validating plan config name against MDMS data + validatePlanConfigName(request, mdmsData); + + // Validate the user information in the request + commonUtil.validateUserInfo(request.getRequestInfo()); + + // Validates the vehicle id from additional details object against the data from mdms v2 + validateVehicleIdsFromAdditionalDetailsAgainstMDMS(request, mdmsV2Data); + } /** - * Validates the assumption values against the assumption keys in the plan configuration. - * If an operation uses an inactive assumption, throws an exception. + * Validates if plan configuration for the provided name and campaign id already exists * - * @param planConfiguration The plan configuration to validate. + * @param planConfiguration the plan configuration from the create request */ - public void validateAssumptionValue(PlanConfiguration planConfiguration) { - // Collect all active assumption keys - Set activeAssumptionKeys = planConfiguration.getAssumptions().stream() - .filter(Assumption::getActive) - .map(Assumption::getKey) - .collect(Collectors.toSet()); + private void validateDuplicateRecord(PlanConfiguration planConfiguration) { + List planConfigurationsFromSearch = planConfigRepository.search(PlanConfigurationSearchCriteria.builder() + .tenantId(planConfiguration.getTenantId()) + .campaignId(planConfiguration.getCampaignId()) + .name(planConfiguration.getName()) + .build()); - List operations = planConfiguration.getOperations(); - for (Operation operation : operations) { - // Check if the operation is using an assumption key that is not in the set of active assumption keys - if (operation.getActive() && !activeAssumptionKeys.contains(operation.getAssumptionValue())) { - log.error("Assumption Value " + operation.getAssumptionValue() + " is not present in the list of active Assumption Keys"); - throw new CustomException(ASSUMPTION_VALUE_NOT_FOUND_CODE, ASSUMPTION_VALUE_NOT_FOUND_MESSAGE + " - " + operation.getAssumptionValue()); - } + if (!CollectionUtils.isEmpty(planConfigurationsFromSearch)) { + throw new CustomException(PLAN_CONFIGURATION_ALREADY_EXISTS_CODE, PLAN_CONFIGURATION_ALREADY_EXISTS_MESSAGE); } } + /** + * Validates campaign ID from request against project factory + * + * @param campaignResponse The campaign details response from project factory + */ + private void validateCampaignId(CampaignResponse campaignResponse) { + if (CollectionUtils.isEmpty(campaignResponse.getCampaignDetails())) { + throw new CustomException(NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE, NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE); + } + } /** - * Validates the assumption keys against MDMS data. - * @param request The request containing the plan configuration and the MDMS data. - * @param mdmsData The MDMS data. + * Validates the name of the plan configuration against a regex pattern retrieved from MDMS data. + * + * @param request the plan configuration request containing the plan configuration details + * @param mdmsData the MDMS data containing the name validation regex patterns + * @throws CustomException if the JSONPath evaluation fails, the name validation list from MDMS is empty, + * or the plan configuration name validation fails. */ - public void validateAssumptionKeyAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { + public void validatePlanConfigName(PlanConfigurationRequest request, Object mdmsData) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); - final String jsonPathForAssumption = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_ASSUMPTION + "[*].assumptions[*]"; - List assumptionListFromMDMS = null; + final String jsonPathForNameValidation = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_NAME_VALIDATION + "[*].data"; + List nameValidationListFromMDMS = null; try { - log.info(jsonPathForAssumption); - assumptionListFromMDMS = JsonPath.read(mdmsData, jsonPathForAssumption); + nameValidationListFromMDMS = JsonPath.read(mdmsData, jsonPathForNameValidation); } catch (Exception e) { - log.error(e.getMessage()); + log.error(jsonPathForNameValidation); throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); } - for(Assumption assumption : planConfiguration.getAssumptions()) - { - if(!assumptionListFromMDMS.contains(assumption.getKey())) - { - log.error("Assumption Key " + assumption.getKey() + " is not present in MDMS"); - throw new CustomException(ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_CODE, ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE + " at JSONPath: " + jsonPathForAssumption); - } + if (CollectionUtils.isEmpty(nameValidationListFromMDMS)) { + throw new CustomException(NAME_VALIDATION_LIST_EMPTY_CODE, NAME_VALIDATION_LIST_EMPTY_MESSAGE); + } + + String regexPattern = (String) nameValidationListFromMDMS.get(0); + if (!commonUtil.validateStringAgainstRegex(regexPattern, planConfiguration.getName())) { + throw new CustomException(NAME_VALIDATION_FAILED_CODE, NAME_VALIDATION_FAILED_MESSAGE); } } + /** - * Validates the file store IDs in the provided PlanConfiguration's Resource Mapping list. - * @param planConfiguration The PlanConfiguration to validate. + * Validates the assumption values against the assumption keys in the plan configuration. + * If an operation uses an inactive assumption, throws an exception. + * + * @param planConfiguration The plan configuration to validate. */ - public void validateFilestoreId(PlanConfiguration planConfiguration) { - Set fileStoreIds = planConfiguration.getFiles().stream() - .map(File::getFilestoreId) - .collect(Collectors.toSet()); - List resourceMappingList = planConfiguration.getResourceMapping(); - for (ResourceMapping mapping : resourceMappingList) { - if (!fileStoreIds.contains(mapping.getFilestoreId())) { - log.error("Resource Mapping " + mapping.getMappedTo() + " does not have valid fileStoreId " + mapping.getFilestoreId()); - throw new CustomException(FILESTORE_ID_INVALID_CODE, FILESTORE_ID_INVALID_MESSAGE); - } - } - } /** - * Validates the template identifiers of files in the PlanConfigurationRequest against the list of template identifiers - * obtained from MDMS (Master Data Management System) data. + * Validates the assumption keys against MDMS data. * - * @param request The PlanConfigurationRequest containing the PlanConfiguration to validate. - * @param mdmsData The MDMS data containing template identifiers to validate against. + * @param request The request containing the plan configuration and the MDMS data. + * @param mdmsData The MDMS data. */ - public void validateTemplateIdentifierAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { + public void validateAssumptionKeyAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); - final String jsonPathForTemplateIdentifier = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_UPLOAD_CONFIGURATION + ".*.id"; - final String jsonPathForTemplateIdentifierIsRequired = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_UPLOAD_CONFIGURATION + "[?(@.required == true)].id"; - - List templateIdentifierListFromMDMS = null; - List requiredTemplateIdentifierFromMDMS = null; - Set activeRequiredTemplates = new HashSet<>(); - - try { - log.info(jsonPathForTemplateIdentifier); - templateIdentifierListFromMDMS = JsonPath.read(mdmsData, jsonPathForTemplateIdentifier); - requiredTemplateIdentifierFromMDMS = JsonPath.read(mdmsData, jsonPathForTemplateIdentifierIsRequired); - } catch (Exception e) { - log.error(e.getMessage()); - throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); - } + if (!CollectionUtils.isEmpty(planConfiguration.getAssumptions())) { - for(File file : planConfiguration.getFiles()) - { - if(!templateIdentifierListFromMDMS.contains(file.getTemplateIdentifier())) - { - log.error("Template Identifier " + file.getTemplateIdentifier() + " is not present in MDMS"); - throw new CustomException(TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_CODE, TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_MESSAGE); + Object additionalDetails = request.getPlanConfiguration().getAdditionalDetails(); + if (additionalDetails == null) { + throw new CustomException(ADDITIONAL_DETAILS_MISSING_CODE, ADDITIONAL_DETAILS_MISSING_MESSAGE); } - if (file.getActive()) { // Check if the file is active - String templateIdentifier = file.getTemplateIdentifier(); - if (requiredTemplateIdentifierFromMDMS.contains(templateIdentifier)) { // Check if the template identifier is required - if (!activeRequiredTemplates.add(templateIdentifier)) { // Ensure only one active file per required template identifier - log.error("Only one file with the required Template Identifier should be present " + file.getTemplateIdentifier()); - throw new CustomException(ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_CODE, ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_MESSAGE); - } - } + String jsonPathForAssumption = commonUtil.createJsonPathForAssumption((String) commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_CAMPAIGN_TYPE), + (String) commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_DISTRIBUTION_PROCESS), + (String) commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_REGISTRATION_PROCESS), + (String) commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_RESOURCE_DISTRIBUTION_STRATEGY_CODE), + (String) commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_IS_REGISTRATION_AND_DISTRIBUTION_TOGETHER)); + List assumptionListFromMDMS = null; + try { + log.info(jsonPathForAssumption); + assumptionListFromMDMS = JsonPath.read(mdmsData, jsonPathForAssumption); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); } - } - // Ensure at least one active file for each required template identifier - for (Object requiredTemplate : requiredTemplateIdentifierFromMDMS) { - if (!activeRequiredTemplates.contains(requiredTemplate)) { - log.error("Required Template Identifier " + requiredTemplate + " does not have any active file."); - throw new CustomException(REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_CODE, REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_MESSAGE); - } + Set assumptionSetFromMDMS = new HashSet<>(assumptionListFromMDMS); + planConfiguration.getAssumptions().forEach(assumption -> { + if (assumption.getActive() && assumption.getSource() == Source.MDMS && !assumptionSetFromMDMS.contains(assumption.getKey())) { + log.error(ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE + assumption.getKey()); + throw new CustomException(ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_CODE, ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE + assumption.getKey() + " at JSONPath: " + jsonPathForAssumption); + } + }); } - } - /** - * Validates the operations input against the Master Data Management System (MDMS) data. + * Validates the uniqueness of assumption keys in the provided PlanConfiguration. + * If any duplicate keys are found, a CustomException is thrown. * - * @param request The PlanConfigurationRequest containing the plan configuration and other details. - * @param mdmsData The MDMS data containing the master rule configure inputs. + * @param planConfig the PlanConfiguration object containing a list of Assumptions to validate + * @throws CustomException if a duplicate assumption key is found */ - public void validateOperationsInputAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { - PlanConfiguration planConfiguration = request.getPlanConfiguration(); - List files = planConfiguration.getFiles(); - List templateIds = files.stream() - .map(File::getTemplateIdentifier) - .collect(Collectors.toList()); - List inputFileTypes = files.stream() - .map(File::getInputFileType) - .map(File.InputFileTypeEnum::toString) - .collect(Collectors.toList()); - - final String jsonPathForRuleInputs = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_SCHEMAS; - List ruleInputsListFromMDMS = null; - try { - log.info(jsonPathForRuleInputs); - ruleInputsListFromMDMS = JsonPath.read(mdmsData, jsonPathForRuleInputs); - } catch (Exception e) { - log.error(e.getMessage()); - throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); - } - List allowedColumns = getRuleConfigInputsFromSchema(ruleInputsListFromMDMS, templateIds, inputFileTypes); - planConfiguration.getOperations().stream() - .map(Operation::getOutput) - .forEach(allowedColumns::add); - for (Operation operation : planConfiguration.getOperations()) { - if (!allowedColumns.contains(operation.getInput())) { - log.error("Input Value " + operation.getInput() + " is not present in MDMS Input List"); - throw new CustomException(INPUT_KEY_NOT_FOUND_CODE, INPUT_KEY_NOT_FOUND_MESSAGE); - } - } - } + public void validateAssumptionUniqueness(PlanConfiguration planConfig) { + Set assumptionKeys = new HashSet<>(); - // helper function - public static List getRuleConfigInputsFromSchema(List schemas, List templateIds, List inputFileTypes) { - if (schemas == null) { - return new ArrayList<>(); - } - Set finalData = new HashSet<>(); - for (Object item : schemas) { - LinkedHashMap schemaEntity = (LinkedHashMap) item; - if(!templateIds.contains(schemaEntity.get(MDMS_SCHEMA_SECTION)) || !inputFileTypes.contains(schemaEntity.get(MDMS_SCHEMA_TYPE))) continue; - LinkedHashMap columns = (LinkedHashMap)((LinkedHashMap) schemaEntity.get(MDMS_SCHEMA_SCHEMA)).get(MDMS_SCHEMA_PROPERTIES); - if(columns == null) return new ArrayList<>(); - for(Map.Entry column : columns.entrySet()){ - LinkedHashMap data = column.getValue(); - if(data.get(MDMS_SCHEMA_PROPERTIES_IS_RULE_CONFIGURE_INPUT)){ - finalData.add(column.getKey()); + for (Assumption assumption : planConfig.getAssumptions()) { + if (assumption.getActive() != Boolean.FALSE) { + if (assumptionKeys.contains(assumption.getKey())) { + throw new CustomException(DUPLICATE_ASSUMPTION_KEY_CODE, DUPLICATE_ASSUMPTION_KEY_MESSAGE + assumption.getKey()); } + assumptionKeys.add(assumption.getKey()); } } - return new ArrayList<>(finalData); } - /** - * Validates that the 'mappedTo' values in the list of 'resourceMappings' are unique. - * If a duplicate 'mappedTo' value is found, it logs an error and throws a CustomException. + * Validates the template identifiers of files in the PlanConfigurationRequest against the list of template identifiers + * obtained from MDMS (Master Data Management System) data. * - * @param resourceMappings The list of 'ResourceMapping' objects to validate. - * @throws CustomException If a duplicate 'mappedTo' value is found. + * @param request The PlanConfigurationRequest containing the PlanConfiguration to validate. + * @param mdmsData The MDMS data containing template identifiers to validate against. */ - public static void validateMappedToUniqueness(List resourceMappings) { - Set uniqueMappedToSet = new HashSet<>(); - for (ResourceMapping mapping : resourceMappings) { - String uniqueKey = mapping.getFilestoreId() + "-" + mapping.getMappedTo(); - if (!uniqueMappedToSet.add(uniqueKey)) { - log.error("Duplicate MappedTo " + mapping.getMappedTo() + " for FilestoreId " + mapping.getFilestoreId()); - throw new CustomException(DUPLICATE_MAPPED_TO_VALIDATION_ERROR_CODE, - DUPLICATE_MAPPED_TO_VALIDATION_ERROR_MESSAGE + " - " + mapping.getMappedTo() + " for FilestoreId " + mapping.getFilestoreId()); + public void validateTemplateIdentifierAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { + PlanConfiguration planConfiguration = request.getPlanConfiguration(); + if (!CollectionUtils.isEmpty(planConfiguration.getFiles())) { + final String jsonPathForTemplateIdentifier = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_UPLOAD_CONFIGURATION + ".*.id"; + final String jsonPathForTemplateIdentifierIsRequired = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_UPLOAD_CONFIGURATION + "[?(@.required == true)].id"; + + List templateIdentifierListFromMDMS = null; + List requiredTemplateIdentifierFromMDMS = null; + Set activeRequiredTemplates = new HashSet<>(); + + try { + log.info(jsonPathForTemplateIdentifier); + templateIdentifierListFromMDMS = JsonPath.read(mdmsData, jsonPathForTemplateIdentifier); + requiredTemplateIdentifierFromMDMS = JsonPath.read(mdmsData, jsonPathForTemplateIdentifierIsRequired); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); } + + HashSet templateIdentifierSetFromMDMS = new HashSet<>(templateIdentifierListFromMDMS); + HashSet requiredTemplateIdentifierSetFromMDMS = new HashSet<>(requiredTemplateIdentifierFromMDMS); + + for (File file : planConfiguration.getFiles()) { + if (!templateIdentifierSetFromMDMS.contains(file.getTemplateIdentifier())) { + log.error(TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_MESSAGE + file.getTemplateIdentifier()); + throw new CustomException(TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_CODE, TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_MESSAGE); + } + + if (file.getActive()) { // Check if the file is active + String templateIdentifier = file.getTemplateIdentifier(); + if (requiredTemplateIdentifierSetFromMDMS.contains(templateIdentifier)) { // Check if the template identifier is required + if (!activeRequiredTemplates.add(templateIdentifier)) { // Ensure only one active file per required template identifier + log.error(ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_MESSAGE + file.getTemplateIdentifier()); + throw new CustomException(ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_CODE, ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_MESSAGE); + } + } + } + } + + // Ensure at least one active file for each required template identifier + if(commonUtil.isSetupCompleted(planConfiguration)){ + requiredTemplateIdentifierSetFromMDMS.forEach(requiredTemplate -> { + if (!activeRequiredTemplates.contains(requiredTemplate)) { + log.error("Required Template Identifier " + requiredTemplate + " does not have any active file."); + throw new CustomException(REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_CODE, REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_MESSAGE); + } + }); + } + } } - /** * Validates the search request for plan configurations. + * * @param planConfigurationSearchRequest The search request for plan configurations. */ public void validateSearchRequest(PlanConfigurationSearchRequest planConfigurationSearchRequest) { @@ -276,43 +295,60 @@ private void validateSearchCriteria(PlanConfigurationSearchRequest planConfigura /** * Validates the update request for plan configuration, including assumptions against MDMS data. + * * @param request The update request for plan configuration. */ public void validateUpdateRequest(PlanConfigurationRequest request) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); - String rootTenantId = planConfiguration.getTenantId().split("\\.")[0]; + String rootTenantId = centralInstanceUtil.getStateLevelTenant(planConfiguration.getTenantId()); Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + List mdmsV2Data = mdmsV2Util.fetchMdmsV2Data(request.getRequestInfo(), rootTenantId, MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_SCHEMA_VEHICLE_DETAILS, null); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(request.getRequestInfo(), request.getPlanConfiguration().getCampaignId(), rootTenantId); + + // Validate the existence of the plan configuration in the request + validatePlanConfigExistence(request); - // Validate plan existence - PlanConfiguration planConfigurationFromDB = validatePlanConfigExistence(request); + // Validate if campaign id exists against project factory + validateCampaignId(campaignResponse); + // Validate that the assumption keys in the request are present in the MDMS data validateAssumptionKeyAgainstMDMS(request, mdmsData); - validateAssumptionValue(planConfiguration); - validateFilestoreId(planConfiguration); -// validateFilesActive(planConfigurationFromDB, planConfiguration); + + // Validate that the assumption keys in the request are unique + validateAssumptionUniqueness(planConfiguration); + + //Validating operation's input and assumptionValue fields + validateOperations(request, campaignResponse); + + // Validate that the template identifiers in the request match those in the MDMS data validateTemplateIdentifierAgainstMDMS(request, mdmsData); - validateOperationsInputAgainstMDMS(request, mdmsData); - validateOperationDependencies(planConfiguration); - validateResourceMappingAgainstMDMS(request, mdmsData); - validateMappedToUniqueness(planConfiguration.getResourceMapping()); + + //Validating plan config name against MDMS data + validatePlanConfigName(request, mdmsData); + + // Validate the user information in the request + commonUtil.validateUserInfo(request.getRequestInfo()); + + // Validates the vehicle id from additional details object against the data from mdms v2 + validateVehicleIdsFromAdditionalDetailsAgainstMDMS(request, mdmsV2Data); } /** * Validates the existence of the plan configuration in the repository. + * * @param request The request containing the plan configuration to validate. */ - public PlanConfiguration validatePlanConfigExistence(PlanConfigurationRequest request) { + public void validatePlanConfigExistence(PlanConfigurationRequest request) { // If plan id provided is invalid, throw an exception List planConfigurationList = planConfigRepository.search(PlanConfigurationSearchCriteria.builder() .id(request.getPlanConfiguration().getId()) .build()); - if(CollectionUtils.isEmpty(planConfigurationList)) { + if (CollectionUtils.isEmpty(planConfigurationList)) { throw new CustomException(INVALID_PLAN_CONFIG_ID_CODE, INVALID_PLAN_CONFIG_ID_MESSAGE); } - return planConfigurationList.get(0); } /** @@ -323,102 +359,231 @@ public PlanConfiguration validatePlanConfigExistence(PlanConfigurationRequest re * @throws CustomException If an inactive operation's output is used as input in any other active operation. */ public static void validateOperationDependencies(PlanConfiguration planConfiguration) { - // Collect all active operations' inputs - Set activeInputs = planConfiguration.getOperations().stream() - .filter(Operation::getActive) - .map(Operation::getInput) - .collect(Collectors.toSet()); + if (!CollectionUtils.isEmpty(planConfiguration.getOperations())) { + // Collect all active operations' inputs + Set activeInputs = planConfiguration.getOperations().stream() + .filter(Operation::getActive) + .map(Operation::getInput) + .collect(Collectors.toSet()); + + // Check for each inactive operation + planConfiguration.getOperations().forEach(operation -> { + if (!operation.getActive() && activeInputs.contains(operation.getOutput())) { + log.error(INACTIVE_OPERATION_USED_AS_INPUT_MESSAGE + operation.getOutput()); + throw new CustomException(INACTIVE_OPERATION_USED_AS_INPUT_CODE, INACTIVE_OPERATION_USED_AS_INPUT_MESSAGE + operation.getOutput()); + } + }); + } + } - // Check for each inactive operation - for (Operation operation : planConfiguration.getOperations()) { - if (!operation.getActive() && activeInputs.contains(operation.getOutput())) { - log.error(INACTIVE_OPERATION_USED_AS_INPUT_MESSAGE + operation.getOutput()); - throw new CustomException(INACTIVE_OPERATION_USED_AS_INPUT_CODE, INACTIVE_OPERATION_USED_AS_INPUT_MESSAGE + operation.getOutput()); - } + + /** + * Validates Vehicle ids from additional details against MDMS V2 + * + * @param request plan configuration request + * @param mdmsV2Data mdms v2 data object + */ + public void validateVehicleIdsFromAdditionalDetailsAgainstMDMS(PlanConfigurationRequest request, List mdmsV2Data) { + List vehicleIdsfromAdditionalDetails = commonUtil.extractFieldsFromJsonObject(request.getPlanConfiguration().getAdditionalDetails(), JSON_FIELD_VEHICLE_ID, List.class); + if (!CollectionUtils.isEmpty(vehicleIdsfromAdditionalDetails)) { + List vehicleIdsFromMdms = mdmsV2Data.stream() + .map(Mdms::getId) + .toList(); + + vehicleIdsfromAdditionalDetails.forEach(vehicleId -> { + if (!vehicleIdsFromMdms.contains(vehicleId)) { + log.error("Vehicle Id " + vehicleId + " is not present in MDMS"); + throw new CustomException(VEHICLE_ID_NOT_FOUND_IN_MDMS_CODE, VEHICLE_ID_NOT_FOUND_IN_MDMS_MESSAGE); + } + }); } } - /** - * Validate input (BCode) against MDMS data. - * @param request plan configauration request. - * @param mdmsData MDMS data object. - */ - public void validateResourceMappingAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { - PlanConfiguration planConfiguration = request.getPlanConfiguration(); - List files = planConfiguration.getFiles(); - List templateIds = files.stream() - .map(File::getTemplateIdentifier) - .collect(Collectors.toList()); - List inputFileTypes = files.stream() - .map(File::getInputFileType) - .map(File.InputFileTypeEnum::toString) - .collect(Collectors.toList()); - - final String jsonPathForRuleInputs = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_SCHEMAS; - List ruleInputsListFromMDMS = null; - try { - log.info(jsonPathForRuleInputs); - ruleInputsListFromMDMS = JsonPath.read(mdmsData, jsonPathForRuleInputs); - } catch (Exception e) { - log.error(e.getMessage()); - throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); + /** + * Checks if files are empty or null when the setup action is marked as completed. + * + * @param planConfiguration The plan configuration to check. + */ + private void checkForEmptyFiles(PlanConfiguration planConfiguration) { + if (CollectionUtils.isEmpty(planConfiguration.getFiles())) { + log.error("Files cannot be empty at action = " + SETUP_COMPLETED_ACTION); + throw new CustomException(FILES_NOT_FOUND_CODE, FILES_NOT_FOUND_MESSAGE); } - List requiredColumns = getIsTruePropertyFromSchema(ruleInputsListFromMDMS, templateIds, inputFileTypes); - List resourceMappings = planConfiguration.getResourceMapping(); + } - // Throw a custom exception if no active mappings with BOUNDARY_CODE are found - if(requiredColumns.contains(ServiceConstants.BOUNDARY_CODE)) { - boolean exists = resourceMappings.stream() - .anyMatch(mapping -> mapping.getActive() && mapping.getMappedTo().equals(ServiceConstants.BOUNDARY_CODE)); + /** + * Checks if assumptions are empty or null when the setup action is marked as completed. + * + * @param planConfiguration The plan configuration to check. + */ + private void checkForEmptyAssumption(PlanConfiguration planConfiguration) { + if (CollectionUtils.isEmpty(planConfiguration.getAssumptions())) { + log.error("Assumptions cannot be empty at action = " + SETUP_COMPLETED_ACTION); + throw new CustomException(ASSUMPTIONS_NOT_FOUND_CODE, ASSUMPTIONS_NOT_FOUND_MESSAGE); + } + } - if (!exists) { - throw new CustomException(BOUNDARY_CODE_MAPPING_NOT_FOUND_CODE, BOUNDARY_CODE_MAPPING_NOT_FOUND_MESSAGE); - } + /** + * Checks if operations are empty or null when the setup action is marked as completed. + * + * @param planConfiguration The plan configuration to check. + */ + private void checkForEmptyOperation(PlanConfiguration planConfiguration) { + if (CollectionUtils.isEmpty(planConfiguration.getOperations())) { + log.error("Operations cannot be empty at action = " + SETUP_COMPLETED_ACTION); + throw new CustomException(OPERATIONS_NOT_FOUND_CODE, OPERATIONS_NOT_FOUND_MESSAGE); } + } + + /** + * Validates the inputs and assumption values in the plan configuration after verifying the setup action is completed. + * + * @param request The plan configuration request to validate. + * @param campaignResponse The campaign response containing details for validation. + */ + public void validateOperations(PlanConfigurationRequest request, CampaignResponse campaignResponse) { + PlanConfiguration planConfiguration = request.getPlanConfiguration(); + + if (commonUtil.isSetupCompleted(planConfiguration)) { + performEmptyChecks(planConfiguration); + + // Get shared data upfront + HashSet allowedColumns = getAllowedColumnsFromMDMS( + request, campaignResponse.getCampaignDetails().get(0).getProjectType() + ); + Set activeAssumptionKeys = getActiveAssumptionKeys(planConfiguration); + validateOperationInputs(planConfiguration, allowedColumns, activeAssumptionKeys); + validateOperationAssumptionValues(planConfiguration, allowedColumns, activeAssumptionKeys); } + } /** - * Return all properties that has isTrue flag as a true. - * @param schemas schema object. - * @param templateIds template ids list. - * @param inputFileTypes list of file type. - * @return + * Performs checks for empty files, assumptions, and operations in the plan configuration. + * + * @param planConfiguration The plan configuration to check. + */ + private void performEmptyChecks(PlanConfiguration planConfiguration) { + checkForEmptyFiles(planConfiguration); + checkForEmptyOperation(planConfiguration); + checkForEmptyAssumption(planConfiguration); + } + + /** + * Retrieves allowed columns based on MDMS data and campaign type. + * + * @param request The plan configuration request containing tenant information. + * @param campaignType The type of campaign for which allowed columns are fetched. + * @return A set of allowed column names. */ - public static List getIsTruePropertyFromSchema(List schemas, List templateIds, List inputFileTypes) { - if (schemas == null) { - return new ArrayList<>(); + private HashSet getAllowedColumnsFromMDMS(PlanConfigurationRequest request, String campaignType) { + String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlanConfiguration().getTenantId()); + String uniqueIndentifier = BOUNDARY + DOT_SEPARATOR + MICROPLAN_PREFIX + campaignType; + List mdmsV2Data = mdmsV2Util.fetchMdmsV2Data(request.getRequestInfo(), rootTenantId, MDMS_ADMIN_CONSOLE_MODULE_NAME + DOT_SEPARATOR + MDMS_SCHEMA_ADMIN_SCHEMA, uniqueIndentifier); + List columnNameList = extractPropertyNamesFromAdminSchema(mdmsV2Data.get(0).getData()); + return new HashSet<>(columnNameList); + } + + /** + * Extracts the names of properties defined within the "numberProperties" and "stringProperties" arrays from admin schema. + * + * @param rootNode The root JSON node from which to extract property names. + * @return A list of property names found in "numberProperties" and "stringProperties". + */ + public List extractPropertyNamesFromAdminSchema(JsonNode rootNode) { + List names = new ArrayList<>(); + + // Access the "properties" node directly from the root node + JsonNode propertiesNode = rootNode.path(PROPERTIES); + + // Extract names from "numberProperties" + JsonNode numberProperties = propertiesNode.path(NUMBER_PROPERTIES); + if (numberProperties.isArray()) { + for (JsonNode property : numberProperties) { + String name = property.path(NAME).asText(null); + if (name != null) { + names.add(name); + } + } } - Set finalData = new HashSet<>(); - for (Object item : schemas) { - LinkedHashMap schemaEntity = (LinkedHashMap) item; - if(!templateIds.contains(schemaEntity.get(MDMS_SCHEMA_SECTION)) || !inputFileTypes.contains(schemaEntity.get(MDMS_SCHEMA_TYPE))) continue; - LinkedHashMap columns = (LinkedHashMap)((LinkedHashMap) schemaEntity.get(MDMS_SCHEMA_SCHEMA)).get(MDMS_SCHEMA_PROPERTIES); - if(columns == null) return new ArrayList<>(); - for(Map.Entry column : columns.entrySet()){ - LinkedHashMap data = column.getValue(); - if(data.get(MDMS_SCHEMA_PROPERTIES_IS_REQUIRED)){ - finalData.add(column.getKey()); + + // Extract names from "stringProperties" + JsonNode stringProperties = propertiesNode.path(STRING_PROPERTIES); + if (stringProperties.isArray()) { + for (JsonNode property : stringProperties) { + String name = property.path(NAME).asText(null); + if (name != null) { + names.add(name); } } } - return new ArrayList<>(finalData); + + return names; + } + + /** + * Gets keys of active assumptions in the plan configuration. + * + * @param planConfiguration The plan configuration containing assumptions. + * @return A set of keys of active assumptions. + */ + private Set getActiveAssumptionKeys(PlanConfiguration planConfiguration) { + return planConfiguration.getAssumptions().stream() + .filter(Assumption::getActive) + .map(Assumption::getKey) + .collect(Collectors.toSet()); + } + + /** + * Validates the input values of operations against allowed columns and previous outputs. + * + * @param planConfiguration The plan configuration containing operations. + * @param allowedColumns The allowed column names for input validation. + */ + private void validateOperationInputs(PlanConfiguration planConfiguration, HashSet allowedColumns, Set activeAssumptionKeys) { + // Set to keep track of previous outputs + Set previousOutputs = new HashSet<>(); + + for (Operation operation : planConfiguration.getOperations()) { + // Validate input + if (operation.getActive() && !allowedColumns.contains(operation.getInput()) && !activeAssumptionKeys.contains(operation.getInput()) && !previousOutputs.contains(operation.getInput()) && operation.getSource() == Source.MDMS) { + log.error("Input Value " + operation.getInput() + " is not present in allowed columns or previous outputs"); + throw new CustomException(INPUT_KEY_NOT_FOUND_CODE, INPUT_KEY_NOT_FOUND_MESSAGE + operation.getInput()); + } + + // Add current operation's output to previousOutputs if it's active + if (operation.getActive()) { + previousOutputs.add(operation.getOutput()); + } + } } - public void validateFilesActive(PlanConfiguration planConfigurationFromDB, PlanConfiguration planConfiguration) - { - // Create a map of files from planConfigurationFromDB using the file ID as the key - Map filesFromDBMap = planConfigurationFromDB.getFiles().stream() - .collect(Collectors.toMap(File::getId, file -> file)); - - // Iterate over the files in planConfiguration - for (File file : planConfiguration.getFiles()) { - File dbFile = filesFromDBMap.get(file.getId()); - // If the file exists in planConfigurationFromDB and has been made active after being inactive - if (dbFile == null) { - throw new CustomException("FILES_ACTIVE_STATUS_CHANGE_NOT_ALLOWED", "Files cannot be made active after being inactive, please upload new file"); + /** + * Validates the assumption values of operations against allowed columns, active keys, and previous outputs. + * + * @param planConfiguration The plan configuration containing operations. + * @param allowedColumns The allowed column names for assumption validation. + * @param activeAssumptionKeys The set of active assumption keys. + */ + private void validateOperationAssumptionValues(PlanConfiguration planConfiguration, HashSet allowedColumns, Set activeAssumptionKeys) { + // Set to keep track of previous outputs + Set previousOutputs = new HashSet<>(); + + for (Operation operation : planConfiguration.getOperations()) { + String assumptionValue = operation.getAssumptionValue(); + + // Validate assumption value + if (operation.getActive() && !allowedColumns.contains(assumptionValue) && !activeAssumptionKeys.contains(assumptionValue) && !previousOutputs.contains(assumptionValue) && operation.getSource() == Source.MDMS) { + log.error("Assumption Value " + assumptionValue + " is not present in allowed columns, previous outputs, or active Assumption Keys"); + throw new CustomException(ASSUMPTION_VALUE_NOT_FOUND_CODE, ASSUMPTION_VALUE_NOT_FOUND_MESSAGE + " - " + assumptionValue); + } + + // Add current operation's output to previousOutputs if it's active + if (operation.getActive() && operation.getSource() == Source.MDMS) { + previousOutputs.add(operation.getOutput()); } } } + } diff --git a/health-services/plan-service/src/main/java/digit/service/validator/PlanEmployeeAssignmentValidator.java b/health-services/plan-service/src/main/java/digit/service/validator/PlanEmployeeAssignmentValidator.java new file mode 100644 index 00000000000..772ec6dd133 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/validator/PlanEmployeeAssignmentValidator.java @@ -0,0 +1,349 @@ +package digit.service.validator; + +import digit.config.Configuration; +import digit.repository.PlanEmployeeAssignmentRepository; +import digit.util.*; +import digit.web.models.*; +import digit.web.models.projectFactory.Boundary; +import digit.web.models.projectFactory.CampaignDetail; +import digit.web.models.projectFactory.CampaignResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.Role; +import org.egov.common.contract.user.UserDetailResponse; +import org.egov.common.utils.MultiStateInstanceUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.*; + +import java.util.*; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class PlanEmployeeAssignmentValidator { + + private MultiStateInstanceUtil centralInstanceUtil; + + private MdmsUtil mdmsUtil; + + private UserUtil userUtil; + + private CommonUtil commonUtil; + + private CampaignUtil campaignUtil; + + private PlanEmployeeAssignmentRepository repository; + + private Configuration config; + + public PlanEmployeeAssignmentValidator(MultiStateInstanceUtil centralInstanceUtil, MdmsUtil mdmsUtil, UserUtil userUtil, CommonUtil commonUtil, CampaignUtil campaignUtil, PlanEmployeeAssignmentRepository repository, Configuration config) { + this.centralInstanceUtil = centralInstanceUtil; + this.mdmsUtil = mdmsUtil; + this.userUtil = userUtil; + this.commonUtil = commonUtil; + this.campaignUtil = campaignUtil; + this.repository = repository; + this.config = config; + } + + /** + * This method validates the create request for plan employee assignment. + * + * @param request The create request for plan employee assignment + */ + public void validateCreate(PlanEmployeeAssignmentRequest request) { + PlanEmployeeAssignment planEmployeeAssignment = request.getPlanEmployeeAssignment(); + String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlanEmployeeAssignment().getTenantId()); + List planConfigurations = commonUtil.searchPlanConfigId(planEmployeeAssignment.getPlanConfigurationId(), rootTenantId); + UserDetailResponse userDetailResponse = userUtil.fetchUserDetail(userUtil.getUserSearchReq(request.getRequestInfo(), planEmployeeAssignment.getEmployeeId(), planEmployeeAssignment.getTenantId())); + + // Validate if a same assignment already exists + validateDuplicateRecord(request); + + // Validate if plan config id exists + validatePlanConfigId(planConfigurations); + + // Validate role of employee against User Service + validateRoleAgainstUserService(planEmployeeAssignment, userDetailResponse); + + // Validate if role of employee is a conflicting role + validateRoleConflict(planEmployeeAssignment); + + // Validate campaign id, employee jurisdiction and highest root jurisdiction in case of Root role + validateCampaignDetails(planConfigurations.get(0).getCampaignId(), rootTenantId, request); + + } + + /** + * This method validates the provided roles of the employee against User Service + * + * @param planEmployeeAssignment The plan employee assignment provided in request + * @param userDetailResponse The user detail response from user service for the provided employeeId + */ + private void validateRoleAgainstUserService(PlanEmployeeAssignment planEmployeeAssignment, UserDetailResponse userDetailResponse) { + + // Validate if employee exists against User Service + if (CollectionUtils.isEmpty(userDetailResponse.getUser())) { + throw new CustomException(INVALID_EMPLOYEE_ID_CODE, INVALID_EMPLOYEE_ID_MESSAGE); + } + + List userRolesFromUserService = userDetailResponse.getUser().get(0).getRoles().stream() + .map(Role::getCode) + .toList(); + + if (!userRolesFromUserService.contains(planEmployeeAssignment.getRole())) { + throw new CustomException(INVALID_EMPLOYEE_ROLE_CODE, INVALID_EMPLOYEE_ROLE_MESSAGE); + } + } + + /** + * Validates if the plan employee assignment for the provided details already exists + * + * @param request the employee assignment create request + */ + private void validateDuplicateRecord(PlanEmployeeAssignmentRequest request) { + PlanEmployeeAssignment employeeAssignment = request.getPlanEmployeeAssignment(); + + List planEmployeeAssignmentsFromSearch = repository.search(PlanEmployeeAssignmentSearchCriteria.builder() + .tenantId(employeeAssignment.getTenantId()) + .planConfigurationId(employeeAssignment.getPlanConfigurationId()) + .employeeId(Collections.singletonList(employeeAssignment.getEmployeeId())) + .role(Collections.singletonList(employeeAssignment.getRole())) + .build()); + + if (!CollectionUtils.isEmpty(planEmployeeAssignmentsFromSearch)) { + throw new CustomException(PLAN_EMPLOYEE_ASSIGNMENT_ALREADY_EXISTS_CODE, PLAN_EMPLOYEE_ASSIGNMENT_ALREADY_EXISTS_MESSAGE); + } + } + + /** + * Validates that employee with National role is assigned to the highest root jurisdiction only against MDMS + * + * @param planEmployeeAssignment The plan employee assignment provided in request + * @param mdmsData mdms data from mdms v2 + * @param campaignDetail the campaign details for the corresponding campaign id + */ + private void validateRootEmployeeJurisdiction(PlanEmployeeAssignment planEmployeeAssignment, Object mdmsData, CampaignDetail campaignDetail) { + if (planEmployeeAssignment.getRole().contains(ROOT_PREFIX)) { + Set jurisdiction = planEmployeeAssignment.getJurisdiction(); + + // Validate that National role employee should not have more than one jurisdiction assigned + if (jurisdiction.size() > 1) { + throw new CustomException(INVALID_ROOT_EMPLOYEE_JURISDICTION_CODE, INVALID_ROOT_EMPLOYEE_JURISDICTION_MESSAGE); + } + + String rootLevelJurisdiction = jurisdiction.stream().findFirst().orElse(null); + + // Fetch the highest hierarchy for Microplan from MDMS + String highestHierarchy = commonUtil.getMicroplanHierarchy(mdmsData).get(HIGHEST_HIERARCHY_FIELD_FOR_MICROPLAN); + + // Filter out the boundary details for the jurisdiction assigned to employee + // Throw exception if jurisdiction assigned to Root role employee is not the highest hierarchy + campaignDetail.getBoundaries().stream() + .filter(boundary -> boundary.getCode().equals(rootLevelJurisdiction)) + .forEach(boundary -> { + if (!boundary.getType().toLowerCase().equals(highestHierarchy)) { + throw new CustomException(INVALID_ROOT_EMPLOYEE_JURISDICTION_CODE, INVALID_ROOT_EMPLOYEE_JURISDICTION_MESSAGE); + } + }); + } + } + + /** + * This method checks if the employee's role provided is a conflicting role against the role map. + * + * @param planEmployeeAssignment The plan employee assignment provided in request + */ + private void validateRoleConflict(PlanEmployeeAssignment planEmployeeAssignment) { + + // Fetch the role mappings from the configuration + Map roleMap = config.getRoleMap(); + + // Check if the role of the employee exists in the role map + if (roleMap.containsKey(planEmployeeAssignment.getRole())) { + + // Fetch existing role assignments for the employee based on their tenant, planConfig Id, and employee ID + // The search is conducted using the conflicting role + List response = repository.search(PlanEmployeeAssignmentSearchCriteria.builder() + .tenantId(planEmployeeAssignment.getTenantId()) + .planConfigurationId(planEmployeeAssignment.getPlanConfigurationId()) + .employeeId(Collections.singletonList(planEmployeeAssignment.getEmployeeId())) + .role(Collections.singletonList(roleMap.get(planEmployeeAssignment.getRole()))).build()); + + // If there are any conflicting assignments found, throw a custom exception + if (!CollectionUtils.isEmpty(response)) { + throw new CustomException(INVALID_EMPLOYEE_ROLE_CODE, INVALID_EMPLOYEE_ROLE_MESSAGE); + } + } + } + + /** + * This method validates campaign id and employee's jurisdiction against project factory + * If the employee has a national role, it validates that the employee has the highest root jurisdiction only + * + * @param campaignId the campaign id corresponding to the plan config id provided in the request + * @param tenantId the tenant id provided in the request + * @param planEmployeeAssignmentRequest the plan employee assignment request provided + */ + private void validateCampaignDetails(String campaignId, String tenantId, PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest) { + PlanEmployeeAssignment planEmployeeAssignment = planEmployeeAssignmentRequest.getPlanEmployeeAssignment(); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(planEmployeeAssignmentRequest.getRequestInfo(), campaignId, tenantId); + Object mdmsData = mdmsUtil.fetchMdmsData(planEmployeeAssignmentRequest.getRequestInfo(), tenantId); + + // Validate if campaign id exists against project factory + validateCampaignId(campaignResponse); + + // Validate the provided jurisdiction for the plan employee assignment + validateEmployeeAssignmentJurisdiction(campaignResponse.getCampaignDetails().get(0), planEmployeeAssignment); + + // Validates the jurisdiction assigned to Root role employee against MDMS + validateRootEmployeeJurisdiction(planEmployeeAssignment, mdmsData, campaignResponse.getCampaignDetails().get(0)); + + // Validates the jurisdiction assigned to a non-Root employee against MDMS + validateEmployeeJurisdiction(planEmployeeAssignment, mdmsData, campaignResponse.getCampaignDetails().get(0)); + } + + /** + * Validates that a non-Root role employee is not assigned to the highest or lowest hierarchy against MDMS + * + * @param planEmployeeAssignment The plan employee assignment provided in request + * @param mdmsData mdms data from mdms v2 + * @param campaignDetail the campaign details for the corresponding campaign id + */ + private void validateEmployeeJurisdiction(PlanEmployeeAssignment planEmployeeAssignment, Object mdmsData, CampaignDetail campaignDetail) { + if (!planEmployeeAssignment.getRole().contains(ROOT_PREFIX)) { + Set jurisdiction = planEmployeeAssignment.getJurisdiction(); + + // Fetch the highest and lowest hierarchy for Microplan from MDMS + Map hierarchyMap = commonUtil.getMicroplanHierarchy(mdmsData); + String lowestHierarchy = hierarchyMap.get(LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN); + String highestHierarchy = hierarchyMap.get(HIGHEST_HIERARCHY_FIELD_FOR_MICROPLAN); + + // Filter out the boundary details for the jurisdiction assigned to employee + // Simultaneously validating if employee is assigned to lowest or highest hierarchy + campaignDetail.getBoundaries().stream() + .filter(boundary -> jurisdiction.contains(boundary.getCode())) + .forEach(boundary -> { + if (boundary.getType().toLowerCase().equals(lowestHierarchy) || + boundary.getType().toLowerCase().equals(highestHierarchy)) { + throw new CustomException(INVALID_EMPLOYEE_JURISDICTION_CODE, INVALID_EMPLOYEE_JURISDICTION_MESSAGE); + } + }); + } + } + + /** + * This method validates if employee's jurisdiction exist in campaign details + * + * @param campaignDetail the campaign details for the corresponding campaign id + * @param planEmployeeAssignment the plan employee assignment provided in request + */ + private void validateEmployeeAssignmentJurisdiction(CampaignDetail campaignDetail, PlanEmployeeAssignment planEmployeeAssignment) { + + // Collect all boundary code for the campaign + Set boundaryCode = campaignDetail.getBoundaries().stream() + .filter(boundary -> planEmployeeAssignment.getHierarchyLevel().equals(boundary.getType())) + .map(Boundary::getCode) + .collect(Collectors.toSet()); + + if(CollectionUtils.isEmpty(boundaryCode)) { + throw new CustomException(INVALID_HIERARCHY_LEVEL_CODE, INVALID_HIERARCHY_LEVEL_MESSAGE); + } + + planEmployeeAssignment.getJurisdiction() + .forEach(jurisdiction -> { + if (!boundaryCode.contains(jurisdiction)) { + throw new CustomException(INVALID_JURISDICTION_CODE, INVALID_JURISDICTION_MESSAGE); + } + }); + + } + + /** + * This method validates if the campaign id provided in the request exists + * + * @param campaignResponse The campaign details response from project factory + */ + private void validateCampaignId(CampaignResponse campaignResponse) { + if (CollectionUtils.isEmpty(campaignResponse.getCampaignDetails())) { + throw new CustomException(NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE, NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE); + } + } + + /** + * This method validates if the plan configuration id provided in the request exists + * + * @param planConfigurations The list of plan configuration for the provided plan config id + */ + private void validatePlanConfigId(List planConfigurations) { + if (CollectionUtils.isEmpty(planConfigurations)) { + throw new CustomException(INVALID_PLAN_CONFIG_ID_CODE, INVALID_PLAN_CONFIG_ID_MESSAGE); + } + } + + /** + * Validates the search request for plan employee assignment + * + * @param request the request to search plan employee assignment + */ + public void validateSearch(PlanEmployeeAssignmentSearchRequest request) { + PlanEmployeeAssignmentSearchCriteria searchCriteria = request.getPlanEmployeeAssignmentSearchCriteria(); + if (Objects.isNull(searchCriteria)) { + throw new CustomException(SEARCH_CRITERIA_EMPTY_CODE, SEARCH_CRITERIA_EMPTY_MESSAGE); + } + + if (StringUtils.isEmpty(searchCriteria.getTenantId())) { + throw new CustomException(TENANT_ID_EMPTY_CODE, TENANT_ID_EMPTY_MESSAGE); + } + + if (StringUtils.isEmpty(searchCriteria.getPlanConfigurationId())) { + throw new CustomException(PLAN_CONFIG_ID_EMPTY_CODE, PLAN_CONFIG_ID_EMPTY_MESSAGE); + } + } + + /** + * This method validates the update request for plan employee assignment. + * + * @param request The update request for plan employee assignment. + */ + public void validateUpdate(PlanEmployeeAssignmentRequest request) { + PlanEmployeeAssignment planEmployeeAssignment = request.getPlanEmployeeAssignment(); + String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlanEmployeeAssignment().getTenantId()); + List planConfigurations = commonUtil.searchPlanConfigId(planEmployeeAssignment.getPlanConfigurationId(), rootTenantId); + + // Validate if Plan employee assignment exists + validatePlanEmployeeAssignmentExistance(planEmployeeAssignment); + + // Validate campaign id and employee jurisdiction + validateCampaignDetails(planConfigurations.get(0).getCampaignId(), rootTenantId, request); + + } + + /** + * This method validates if the plan employee assignment provided in the update request exists + * + * @param planEmployeeAssignment The plan employee assignment details from the request + */ + private void validatePlanEmployeeAssignmentExistance(PlanEmployeeAssignment planEmployeeAssignment) { + if (ObjectUtils.isEmpty(planEmployeeAssignment.getId())) { + throw new CustomException(PLAN_EMPLOYEE_ASSIGNMENT_ID_EMPTY_CODE, PLAN_EMPLOYEE_ASSIGNMENT_ID_EMPTY_MESSAGE); + } + + // Validates the existence of plan employee assignment + List planEmployeeAssignments = repository.search(PlanEmployeeAssignmentSearchCriteria.builder() + .tenantId(planEmployeeAssignment.getTenantId()) + .id(planEmployeeAssignment.getId()) + .role(Collections.singletonList(planEmployeeAssignment.getRole())) + .planConfigurationId(planEmployeeAssignment.getPlanConfigurationId()) + .employeeId(Collections.singletonList(planEmployeeAssignment.getEmployeeId())) + .build()); + + if (CollectionUtils.isEmpty(planEmployeeAssignments)) { + throw new CustomException(INVALID_PLAN_EMPLOYEE_ASSIGNMENT_CODE, INVALID_PLAN_EMPLOYEE_ASSIGNMENT_MESSAGE); + } + } + +} diff --git a/health-services/plan-service/src/main/java/digit/service/validator/PlanFacilityValidator.java b/health-services/plan-service/src/main/java/digit/service/validator/PlanFacilityValidator.java new file mode 100644 index 00000000000..dd7b251eaf1 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/validator/PlanFacilityValidator.java @@ -0,0 +1,301 @@ +package digit.service.validator; + +import com.jayway.jsonpath.JsonPath; +import digit.repository.PlanConfigurationRepository; +import digit.repository.PlanFacilityRepository; +import digit.service.enrichment.PlanFacilityEnricher; +import digit.util.*; +import digit.web.models.*; +import digit.web.models.facility.Facility; +import digit.web.models.facility.FacilityResponse; +import digit.web.models.projectFactory.CampaignDetail; +import digit.web.models.projectFactory.CampaignResponse; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.utils.MultiStateInstanceUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import static digit.config.ServiceConstants.*; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +import digit.web.models.projectFactory.Boundary; + +@Component +@Slf4j +public class PlanFacilityValidator { + private PlanFacilityRepository planFacilityRepository; + private PlanConfigurationRepository planConfigurationRepository; + private CampaignUtil campaignUtil; + private MultiStateInstanceUtil centralInstanceUtil; + private MdmsUtil mdmsUtil; + private FacilityUtil facilityUtil; + private CommonUtil commonUtil; + private PlanFacilityEnricher enrichment; + + public PlanFacilityValidator(PlanFacilityRepository planFacilityRepository, PlanConfigurationRepository planConfigurationRepository, CampaignUtil campaignUtil, MultiStateInstanceUtil centralInstanceUtil, MdmsUtil mdmsUtil, FacilityUtil facilityUtil, CommonUtil commonUtil, PlanFacilityEnricher enrichment) { + this.planFacilityRepository = planFacilityRepository; + this.planConfigurationRepository = planConfigurationRepository; + this.campaignUtil = campaignUtil; + this.centralInstanceUtil = centralInstanceUtil; + this.mdmsUtil = mdmsUtil; + this.facilityUtil = facilityUtil; + this.commonUtil = commonUtil; + this.enrichment = enrichment; + } + + /** + * This method validates the Plan Facility Create request. + * It performs multiple validations such as plan configuration, facility existence, + * and campaign-related validations. + * + * @param planFacilityRequest + */ + public void validatePlanFacilityCreate(@Valid PlanFacilityRequest planFacilityRequest) { + // Retrieve the root-level tenant ID (state-level) based on the facility's tenant ID + String rootTenantId = centralInstanceUtil.getStateLevelTenant(planFacilityRequest.getPlanFacility().getTenantId()); + + // Validate duplicate records for plan facility + validateDuplicateRecords(planFacilityRequest); + + // Validate PlanConfiguration Existence and fetch the plan configuration details using the PlanConfigurationId + List planConfigurations = fetchPlanConfigurationById(planFacilityRequest.getPlanFacility().getPlanConfigurationId(), rootTenantId); + + // Validate facility existence + validateFacilityExistence(planFacilityRequest); + + // Validate service boundaries and residing boundaries with campaign id + validateCampaignDetails(planConfigurations.get(0).getCampaignId(), rootTenantId, planFacilityRequest); + } + + /** + * Validates if plan facility linkage for the provided planConfiguration id and facility id already exists + * + * @param planFacilityRequest The plan facility linkage create request + */ + private void validateDuplicateRecords(@Valid PlanFacilityRequest planFacilityRequest) { + PlanFacility planFacility = planFacilityRequest.getPlanFacility(); + + PlanFacilitySearchCriteria searchCriteria = PlanFacilitySearchCriteria.builder().planConfigurationId(planFacility.getPlanConfigurationId()).facilityId(planFacility.getFacilityId()).build(); + + List planFacilityList = planFacilityRepository.search(searchCriteria); + + if (!CollectionUtils.isEmpty(planFacilityList)) { + throw new CustomException(PLAN_FACILITY_LINKAGE_ALREADY_EXISTS_CODE, PLAN_FACILITY_LINKAGE_ALREADY_EXISTS_MESSAGE); + } + } + + /** + * This method validates the Plan Facility Update request. + * It performs multiple validations such as plan facility existence + * and campaign-related validations. + * + * @param planFacilityRequest + */ + public void validatePlanFacilityUpdate(PlanFacilityRequest planFacilityRequest) { + String rootTenantId = centralInstanceUtil.getStateLevelTenant(planFacilityRequest.getPlanFacility().getTenantId()); + + //validate plan facility existence + validatePlanFacilityExistence(planFacilityRequest); + + List planConfigurations = fetchPlanConfigurationById(planFacilityRequest.getPlanFacility().getPlanConfigurationId(), rootTenantId); + + //validate service boundaries and residing boundaries with campaign id + validateCampaignDetails(planConfigurations.get(0).getCampaignId(), rootTenantId, planFacilityRequest); + } + + /** + * This method validates campaign id and service boundaries against project factory + * + * @param campaignId the campaign id corresponding to the plan config id provided in the request + * @param rootTenantId the tenant id provided in the request + * @param planFacilityRequest the plan facility request provided + */ + private void validateCampaignDetails(String campaignId, String rootTenantId, PlanFacilityRequest planFacilityRequest) { + PlanFacility planFacility = planFacilityRequest.getPlanFacility(); + Object mdmsData = mdmsUtil.fetchMdmsData(planFacilityRequest.getRequestInfo(), rootTenantId); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(planFacilityRequest.getRequestInfo(), campaignId, rootTenantId); + + // Validate hierarchy type for campaign + Map hierarchyMap = commonUtil.getMicroplanHierarchy(mdmsData); + String lowestHierarchy = hierarchyMap.get(LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN); + + // Collect all boundary code for the campaign + Set boundaryCodes = fetchBoundaryCodes(campaignResponse.getCampaignDetails().get(0), lowestHierarchy); + + // Validate residing boundaries + validateResidingBoundaries(boundaryCodes, planFacility); + + // Validate service boundaries + validateServiceBoundaries(boundaryCodes, planFacility); + + //Enrich jurisdiction mapping and boundary ancestral path + enrichment.enrichJurisdictionMapping(planFacilityRequest, campaignResponse.getCampaignDetails().get(0).getHierarchyType()); + } + + /** + * This method returns boundary code for the campaign + * + * @param campaignDetail + * @param lowestHierarchy + */ + private Set fetchBoundaryCodes(CampaignDetail campaignDetail, String lowestHierarchy) { + Set boundaryCodes = campaignDetail.getBoundaries().stream() + .filter(boundary -> lowestHierarchy.equals(boundary.getType().toLowerCase())) + .map(Boundary::getCode) + .collect(Collectors.toSet()); + + return boundaryCodes; + } + + /** + * This method validates if residing boundaries exist in campaign details + * + * @param boundaryCodes + * @param planFacility + */ + private void validateResidingBoundaries(Set boundaryCodes, PlanFacility planFacility) { + String residingBoundary = planFacility.getResidingBoundary(); + if (residingBoundary != null && !boundaryCodes.contains(residingBoundary)) { + throw new CustomException(INVALID_RESIDING_BOUNDARY_CODE, INVALID_RESIDING_BOUNDARY_MESSAGE); + } + } + + /** + * This method validates if service boundaries exist in campaign details + * + * @param boundaryCodes + * @param planFacility + */ + private void validateServiceBoundaries(Set boundaryCodes, PlanFacility planFacility) { + List serviceBoundaries = planFacility.getServiceBoundaries(); + + // Check for duplicate service boundaries + Set uniqueBoundaries = new HashSet<>(serviceBoundaries); + if (uniqueBoundaries.size() != serviceBoundaries.size()) { + throw new CustomException(INVALID_SERVICE_BOUNDARY_CODE, "Duplicate service boundaries are not allowed"); + } + + planFacility.getServiceBoundaries().forEach(serviceBoundary -> { + if (!boundaryCodes.contains(serviceBoundary)) { + throw new CustomException(INVALID_SERVICE_BOUNDARY_CODE, INVALID_SERVICE_BOUNDARY_MESSAGE); + } + }); + } + + /** + * This method validates if the hierarchy type provided in the request exists + * + * @param campaignResponse + * @param mdmsData + */ + private String validateHierarchyType(CampaignResponse campaignResponse, Object mdmsData) { + // Get the hierarchy type from the campaign response + String hierarchyType = campaignResponse.getCampaignDetails().get(0).getHierarchyType(); + + // Define the JSON path to fetch hierarchy configurations from MDMS data + final String jsonPathForHierarchy = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_HIERARCHY_CONFIG + "[*]"; + + List> hierarchyConfigList = null; + try { + hierarchyConfigList = JsonPath.read(mdmsData, jsonPathForHierarchy); + } catch (Exception e) { + throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); + } + + // Iterate through the hierarchy configuration list + for (Map hierarchyConfig : hierarchyConfigList) { + if (hierarchyType.equals(hierarchyConfig.get(MDMS_MASTER_HIERARCHY))) { + // Return the lowest hierarchy value from the configuration + return (String) hierarchyConfig.get(LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN); + } + } + // Throw exception if no matching hierarchy is found + throw new CustomException(HIERARCHY_NOT_FOUND_IN_MDMS_CODE, HIERARCHY_NOT_FOUND_IN_MDMS_MESSAGE); + } + + /** + * This method validates if the plan facility id provided in the update request exists + * + * @param planFacilityRequest + */ + private void validatePlanFacilityExistence(PlanFacilityRequest planFacilityRequest) { + List planFacilityListFromSearch = planFacilityRepository.search(PlanFacilitySearchCriteria.builder() + .ids(Collections.singleton(planFacilityRequest.getPlanFacility().getId())) + .build()); + + // If plan facility id provided is invalid, throw an exception + if (CollectionUtils.isEmpty(planFacilityListFromSearch)) { + throw new CustomException(INVALID_PLAN_FACILITY_ID_CODE, INVALID_PLAN_FACILITY_ID_MESSAGE); + } + + enrichInitialServiceBoundaries(planFacilityListFromSearch, planFacilityRequest); + } + + private void enrichInitialServiceBoundaries(List planFacilityListFromSearch, PlanFacilityRequest planFacilityRequest) { + + List initiallySetServiceBoundaries = planFacilityListFromSearch.get(0).getServiceBoundaries(); + planFacilityRequest.getPlanFacility().setInitiallySetServiceBoundaries(initiallySetServiceBoundaries); + } + + /** + * Searches the plan config based on the plan config id provided + * + * @param planConfigurationId + * @param tenantId + * @return + */ + public List fetchPlanConfigurationById(String planConfigurationId, String tenantId) { + List planConfigurations = planConfigurationRepository.search(PlanConfigurationSearchCriteria.builder() + .id(planConfigurationId) + .tenantId(tenantId) + .build()); + log.info("planConfigurations: " + planConfigurations); + + // Validate planConfiguration exists + if (CollectionUtils.isEmpty(planConfigurations)) { + throw new CustomException(INVALID_PLAN_CONFIG_ID_CODE, INVALID_PLAN_CONFIG_ID_MESSAGE); + } + + return planConfigurations; + } + + /** + * Validates if the facility with the provided ID exists in the system. + * + * @param planFacilityRequest + */ + private void validateFacilityExistence(PlanFacilityRequest planFacilityRequest) { + FacilityResponse facilityResponse = facilityUtil.fetchFacilityData(planFacilityRequest); + + // Use ObjectUtils and CollectionUtils to handle null or empty checks + if (ObjectUtils.isEmpty(facilityResponse) || CollectionUtils.isEmpty(facilityResponse.getFacilities())) { + throw new CustomException("FACILITY_NOT_FOUND", "Facility with ID " + planFacilityRequest.getPlanFacility().getFacilityId() + " not found in the system."); + } + + enrichFacilityDetails(facilityResponse.getFacilities().get(0), planFacilityRequest); + } + + private void enrichFacilityDetails(Facility facility, PlanFacilityRequest planFacilityRequest) { + String facilityName = facility.getName(); + planFacilityRequest.getPlanFacility().setFacilityName(facilityName); + BigDecimal initialServingPop = BigDecimal.ZERO; + + Map fieldsToBeAdded = new HashMap<>(); + fieldsToBeAdded.put("facilityUsage", facility.getUsage()); + fieldsToBeAdded.put("capacity", facility.getStorageCapacity()); + fieldsToBeAdded.put("facilityStatus", facility.getAddress().getType()); + fieldsToBeAdded.put("facilityType", facility.getUsage()); + fieldsToBeAdded.put("isPermanent", facility.isPermanent()); + fieldsToBeAdded.put("servingPopulation", initialServingPop); + + planFacilityRequest.getPlanFacility().setAdditionalDetails( + commonUtil.updateFieldInAdditionalDetails(planFacilityRequest.getPlanFacility().getAdditionalDetails(), fieldsToBeAdded)); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/service/validator/WorkflowValidator.java b/health-services/plan-service/src/main/java/digit/service/validator/WorkflowValidator.java new file mode 100644 index 00000000000..321cdb36ecc --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/validator/WorkflowValidator.java @@ -0,0 +1,141 @@ +package digit.service.validator; + +import digit.service.PlanService; +import digit.util.CensusUtil; +import digit.web.models.*; +import digit.web.models.census.CensusResponse; +import digit.web.models.census.CensusSearchCriteria; +import digit.web.models.census.CensusSearchRequest; +import org.egov.common.contract.request.RequestInfo; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.util.Map; + +import static digit.config.ServiceConstants.*; +import static digit.config.ServiceConstants.CANNOT_APPROVE_ESTIMATIONS_MESSAGE; + +@Component +public class WorkflowValidator { + + private CensusUtil censusUtil; + + private PlanService planService; + + public WorkflowValidator(CensusUtil censusUtil, PlanService planService) { + this.censusUtil = censusUtil; + this.planService = planService; + } + + public void validateWorkflow(PlanConfigurationRequest planConfigurationRequest) { + if (ObjectUtils.isEmpty(planConfigurationRequest.getPlanConfiguration().getWorkflow())) + return; + + String workflowAction = planConfigurationRequest.getPlanConfiguration().getWorkflow().getAction(); + + if(workflowAction.equals(APPROVE_CENSUS_DATA_ACTION)) { + validateCensusData(planConfigurationRequest); + } else if(workflowAction.equals(FINALIZE_CATCHMENT_MAPPING_ACTION)) { + validateCatchmentMapping(planConfigurationRequest); + } else if(workflowAction.equals(APPROVE_ESTIMATIONS_ACTION)) { + validateResourceEstimations(planConfigurationRequest); + } + } + + /** + * Validates if all the census records are validated before approving census data for the given planConfigId. + * + * @param planConfigurationRequest request with plan config id. + */ + private void validateCensusData(PlanConfigurationRequest planConfigurationRequest) { + PlanConfiguration planConfiguration = planConfigurationRequest.getPlanConfiguration(); + + CensusSearchRequest censusSearchRequest = getCensusSearchRequest(planConfiguration.getTenantId(), planConfiguration.getId(), planConfigurationRequest.getRequestInfo()); + + // Fetches census records for given planConfigId + CensusResponse censusResponse = censusUtil.fetchCensusRecords(censusSearchRequest); + + Map statusCount = censusResponse.getStatusCount(); + Integer totalCount = censusResponse.getTotalCount(); + + // Throws exception if all census records are not validated + if (!statusCount.get(VALIDATED_STATUS).equals(totalCount)) { + throw new CustomException(CANNOT_APPROVE_CENSUS_DATA_CODE, CANNOT_APPROVE_CENSUS_DATA_MESSAGE); + } + } + + /** + * Validates if all boundaries have facility assigned before finalizing catchment mapping for a given planConfigID. + * + * @param planConfigurationRequest request with plan config id. + */ + private void validateCatchmentMapping(PlanConfigurationRequest planConfigurationRequest) { + PlanConfiguration planConfiguration = planConfigurationRequest.getPlanConfiguration(); + + CensusSearchRequest censusSearchRequest = getCensusSearchRequest(planConfiguration.getTenantId(), planConfiguration.getId(), planConfigurationRequest.getRequestInfo()); + + // Fetches all census records for given planConfigId + CensusResponse censusResponse = censusUtil.fetchCensusRecords(censusSearchRequest); + Integer totalCensusCount = censusResponse.getTotalCount(); + + censusSearchRequest.getCensusSearchCriteria().setFacilityAssigned(Boolean.TRUE); + + // Fetches all census records for given planConfigId where facility is assigned + CensusResponse censusWithFacilityAssigned = censusUtil.fetchCensusRecords(censusSearchRequest); + Integer totalCensusWithFacilityAssigned = censusWithFacilityAssigned.getTotalCount(); + + if (!totalCensusCount.equals(totalCensusWithFacilityAssigned)) { + throw new CustomException(CANNOT_FINALIZE_CATCHMENT_MAPPING_CODE, CANNOT_FINALIZE_CATCHMENT_MAPPING_MESSAGE); + } + } + + /** + * Validates if all the plan estimations are validated before approving estimations for the given planConfigId. + * + * @param planConfigurationRequest request with plan config id. + */ + private void validateResourceEstimations(PlanConfigurationRequest planConfigurationRequest) { + PlanConfiguration planConfiguration = planConfigurationRequest.getPlanConfiguration(); + + PlanSearchRequest searchRequest = getPlanSearchRequest(planConfiguration.getTenantId(), planConfiguration.getId(), planConfigurationRequest.getRequestInfo()); + + // Fetches plans for given planConfigId + PlanResponse planResponse = planService.searchPlan(searchRequest); + + Map statusCount = planResponse.getStatusCount(); + Integer totalCount = planResponse.getTotalCount(); + + // Throws exception if all plans are not validated + if (!statusCount.get(VALIDATED_STATUS).equals(totalCount)) { + throw new CustomException(CANNOT_APPROVE_ESTIMATIONS_CODE, CANNOT_APPROVE_ESTIMATIONS_MESSAGE); + } + } + + // Prepares Census search request for given planConfigId + private CensusSearchRequest getCensusSearchRequest(String tenantId, String planConfigId, RequestInfo requestInfo) { + CensusSearchCriteria searchCriteria = CensusSearchCriteria.builder() + .tenantId(tenantId) + .source(planConfigId) + .build(); + + return CensusSearchRequest.builder() + .requestInfo(requestInfo) + .censusSearchCriteria(searchCriteria) + .build(); + } + + // Prepares Plan search request for given planConfigId + private PlanSearchRequest getPlanSearchRequest(String tenantId, String planConfigId, RequestInfo requestInfo) { + PlanSearchCriteria searchCriteria = PlanSearchCriteria.builder() + .tenantId(tenantId) + .planConfigurationId(planConfigId) + .build(); + + return PlanSearchRequest.builder() + .requestInfo(requestInfo) + .planSearchCriteria(searchCriteria) + .build(); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/service/workflow/WorkflowService.java b/health-services/plan-service/src/main/java/digit/service/workflow/WorkflowService.java new file mode 100644 index 00000000000..24932950df8 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/workflow/WorkflowService.java @@ -0,0 +1,432 @@ +package digit.service.workflow; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.config.Configuration; +import digit.repository.ServiceRequestRepository; +import digit.service.PlanEmployeeService; +import digit.service.validator.PlanConfigurationValidator; +import digit.util.CommonUtil; +import digit.web.models.*; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.Workflow; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.User; +import org.egov.common.contract.workflow.*; +import org.egov.common.utils.AuditDetailsEnrichmentUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.*; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.*; +import static digit.config.ServiceConstants.NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE; + +@Service +@Slf4j +public class WorkflowService { + + private ServiceRequestRepository serviceRequestRepository; + + private Configuration config; + + private ObjectMapper mapper; + + private CommonUtil commonUtil; + + private PlanEmployeeService planEmployeeService; + + private PlanConfigurationValidator planConfigurationValidator; + + private RestTemplate restTemplate; + + public WorkflowService(ServiceRequestRepository serviceRequestRepository, Configuration config, ObjectMapper mapper, CommonUtil commonUtil, PlanEmployeeService planEmployeeService, PlanConfigurationValidator planConfigurationValidator, RestTemplate restTemplate) { + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.mapper = mapper; + this.commonUtil = commonUtil; + this.planEmployeeService = planEmployeeService; + this.planConfigurationValidator = planConfigurationValidator; + this.restTemplate = restTemplate; + } + + /** + * Integrates with the workflow for the given plan configuration request. + * If the action is null, it does not proceed with integration. + * + * @param planConfigurationRequest The request containing the plan configuration to integrate with the workflow. + */ + public void invokeWorkflowForStatusUpdate(PlanConfigurationRequest planConfigurationRequest) { + if (ObjectUtils.isEmpty(planConfigurationRequest.getPlanConfiguration().getWorkflow())) + return; + + ProcessInstanceRequest processInstanceRequest = createWorkflowRequest(planConfigurationRequest); + ProcessInstanceResponse processInstanceResponse = callWorkflowTransition(processInstanceRequest); + + // Setting the status back to the plan configuration object from workflow response + planConfigurationRequest.getPlanConfiguration().setStatus(processInstanceResponse.getProcessInstances().get(0).getState().getState()); + } + + /** + * Integrates with the workflow for the given plan request. + * If the action is null, it does not proceed with integration. + * + * @param planRequest The request containing the plan estimate to integrate with the workflow. + */ + public void invokeWorkflowForStatusUpdate(PlanRequest planRequest) { + if (ObjectUtils.isEmpty(planRequest.getPlan().getWorkflow())) + return; + + ProcessInstanceRequest processInstanceRequest = createWorkflowRequest(planRequest); + ProcessInstanceResponse processInstanceResponse = callWorkflowTransition(processInstanceRequest); + + // Setting the status back to the plan configuration object from workflow response + planRequest.getPlan().setStatus(processInstanceResponse.getProcessInstances().get(0).getState().getState()); + + // Enrich audit details after auto assignment is complete + planRequest.getPlan().setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails( planRequest.getPlan().getAuditDetails(), planRequest.getRequestInfo(), Boolean.FALSE)); + + } + + /** + * Calls the workflow transition service and retrieves the process instance response. + * + * @param processInstanceRequest The request containing process instance details for the workflow transition. + * @return The response containing details of the process instances after the transition. + * @throws CustomException if there is an error during the workflow integration. + */ + public ProcessInstanceResponse callWorkflowTransition(ProcessInstanceRequest processInstanceRequest) { + ProcessInstanceResponse processInstanceResponse; + try { + Object response = serviceRequestRepository.fetchResult(getWorkflowTransitionUri(), processInstanceRequest); + processInstanceResponse = mapper.convertValue(response, ProcessInstanceResponse.class); + } catch (Exception e) { + throw new CustomException(WORKFLOW_INTEGRATION_ERROR_CODE, WORKFLOW_INTEGRATION_ERROR_MESSAGE + e.getMessage()); + } + + return processInstanceResponse; + } + + /** + * Creates a workflow request from the given plan configuration request. + * + * @param planConfigurationRequest The request containing the plan configuration to create a workflow request. + * @return The constructed process instance request for the workflow. + */ + public ProcessInstanceRequest createWorkflowRequest(PlanConfigurationRequest planConfigurationRequest) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + ProcessInstance processInstance = ProcessInstance.builder() + .businessId(planConfig.getId()) + .tenantId(planConfig.getTenantId()) + .businessService(PLAN_CONFIGURATION_BUSINESS_SERVICE) + .moduleName(MODULE_NAME_VALUE) + .action(planConfig.getWorkflow().getAction()) + .comment(planConfig.getWorkflow().getComments()) + .documents(planConfig.getWorkflow().getDocuments()) + .build(); + + enrichAssignesInProcessInstance(processInstance, planConfig.getWorkflow()); + + return ProcessInstanceRequest.builder() + .requestInfo(planConfigurationRequest.getRequestInfo()) + .processInstances(Collections.singletonList(processInstance)) + .build(); + } + + /** + * Creates a workflow request from the given plan configuration request. + * + * @param planRequest The request containing the plan to create a workflow request. + * @return The constructed process instance request for the workflow. + */ + public ProcessInstanceRequest createWorkflowRequest(PlanRequest planRequest) { + Plan plan = planRequest.getPlan(); + ProcessInstance processInstance = ProcessInstance.builder() + .businessId(plan.getId()) + .tenantId(plan.getTenantId()) + .businessService(PLAN_ESTIMATION_BUSINESS_SERVICE) + .moduleName(MODULE_NAME_VALUE) + .action(plan.getWorkflow().getAction()) + .comment(plan.getWorkflow().getComments()) + .documents(plan.getWorkflow().getDocuments()) + .build(); + + List assignee = getAssigneeForAutoAssignment(plan, planRequest.getRequestInfo()); + + // Set assignees for send back actions + if (config.getWfSendBackActions().contains(plan.getWorkflow().getAction())) { + assignee = Collections.singletonList(plan.getAuditDetails().getLastModifiedBy()); + } + + // Set Assignee + if(!ObjectUtils.isEmpty(assignee)) + plan.getWorkflow().setAssignes(assignee); + + plan.setAssignee(assignee); + + enrichAssignesInProcessInstance(processInstance, plan.getWorkflow()); + + log.info("Process Instance assignes - " + processInstance.getAssignes()); + return ProcessInstanceRequest.builder() + .requestInfo(planRequest.getRequestInfo()) + .processInstances(Collections.singletonList(processInstance)) + .build(); + } + + /** + * Enriches the process instance with assignees from the given workflow. + * + * @param processInstance The process instance to enrich with assignees. + * @param workflow The workflow containing assignees to be added to the process instance. + */ + public void enrichAssignesInProcessInstance(ProcessInstance processInstance, Workflow workflow) { + List userList = CollectionUtils.isEmpty(workflow.getAssignes()) + ? new LinkedList<>() + : workflow.getAssignes().stream() + .map(assignee -> User.builder().uuid(assignee).build()) + .toList(); + + processInstance.setAssignes(userList); + } + + /** + * Constructs the URI for the workflow service transition API. + * + * @return The StringBuilder containing the constructed workflow transition URI. + */ + private StringBuilder getWorkflowTransitionUri() { + return new StringBuilder().append(config.getWfHost()).append(config.getWfTransitionPath()); + } + + /** + * Automatically assigns a list of assignee based on the workflow action and jurisdiction hierarchy. + * Retrieves jurisdiction boundaries from the plan request and searches for matching employee assignments. + * + * For INITIATE actions, assigns the employee from the lowest boundary. + * For INTERMEDIATE actions (non-ROOT_APPROVER), assigns an employee from a higher-level boundary. + * For SEND_BACK actions, assigns the last modified user. + * + * The assignee is set in both the workflow and the plan request. + * + * @param requestInfo auth details for making internal calls + * @param plan the plan object containing workflow and jurisdiction details + */ + private List getAssigneeForAutoAssignment(Plan plan, RequestInfo requestInfo) { + String[] allheirarchysBoundaryCodes = plan.getBoundaryAncestralPath().split(PIPE_REGEX); + String[] heirarchysBoundaryCodes = Arrays.copyOf(allheirarchysBoundaryCodes, allheirarchysBoundaryCodes.length - 1); + + PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = + PlanEmployeeAssignmentSearchCriteria.builder() + .tenantId(plan.getTenantId()) + .jurisdiction(Arrays.stream(heirarchysBoundaryCodes).toList()) + .planConfigurationId(plan.getPlanConfigurationId()) + .role(config.getPlanEstimationApproverRoles()) + .build(); + + //search for plan-employee assignments for the ancestral heirarchy codes. + PlanEmployeeAssignmentResponse planEmployeeAssignmentResponse = planEmployeeService.search(PlanEmployeeAssignmentSearchRequest.builder() + .planEmployeeAssignmentSearchCriteria(planEmployeeAssignmentSearchCriteria) + .requestInfo(requestInfo).build()); + + // Create a map of jurisdiction to list of employeeIds + Map> jurisdictionToEmployeeMap = planEmployeeAssignmentResponse.getPlanEmployeeAssignment().stream() + .filter(assignment -> assignment.getJurisdiction() != null && !assignment.getJurisdiction().isEmpty()) + .flatMap(assignment -> { + String employeeId = assignment.getEmployeeId(); + return assignment.getJurisdiction().stream() + .filter(jurisdiction -> Arrays.asList(heirarchysBoundaryCodes).contains(jurisdiction)) + .map(jurisdiction -> new AbstractMap.SimpleEntry<>(jurisdiction, employeeId)); + }) + .collect(Collectors.groupingBy( + Map.Entry::getKey, // jurisdiction as the key + LinkedHashMap::new, // Preserve insertion order + Collectors.mapping( + Map.Entry::getValue, // employee IDs as values + Collectors.toList() // Collect employee IDs into a List + ) + )); + + List assignee = null; //assignee will remain null in case terminate actions are being taken + + String action = plan.getWorkflow().getAction(); + if (config.getWfInitiateActions().contains(action)) { + for (int i = heirarchysBoundaryCodes.length - 1; i >= 0; i--) { + assignee = jurisdictionToEmployeeMap.get(heirarchysBoundaryCodes[i]); + if (assignee != null) + break; // Stop iterating once an assignee is found + } + } else if (config.getWfIntermediateActions().contains(action)) { + assignee = assignToHigherBoundaryLevel(heirarchysBoundaryCodes, plan, jurisdictionToEmployeeMap); + } + + return assignee; + } + + /** + * Assigns a list of employees from a higher-level jurisdiction in the hierarchy. + * Iterates through boundary codes, checking if they match the assignee's jurisdiction. + * If a higher-level boundary has an assigned employee, returns that employee's ID. + * + * @param heirarchysBoundaryCodes boundary codes representing the hierarchy + * @param plan the object with plan and jurisdiction details + * @param jurisdictionToEmployeeMap map of jurisdiction codes to employee IDs + * @return the employee ID from the higher boundary, or null if + */ + public List assignToHigherBoundaryLevel(String[] heirarchysBoundaryCodes, Plan plan, Map> jurisdictionToEmployeeMap) { + for (int i = heirarchysBoundaryCodes.length - 1; i >= 0; i--) { + String boundaryCode = heirarchysBoundaryCodes[i]; + + // Check if this boundary code is present in assigneeJurisdiction + if (plan.getAssigneeJurisdiction().contains(boundaryCode)) { + + for (int j = i - 1; j >= 0; j--) { + // Check the next higher level in the hierarchy (one index above the match) + String higherBoundaryCode = heirarchysBoundaryCodes[j]; + + // Fetch the employeeId from the map for the higher boundary code + List employeeId = jurisdictionToEmployeeMap.get(higherBoundaryCode); + + // If an employee is found, set them as the assignee and break the loop + if (employeeId != null) { + return employeeId; + } + } + } + } + return null; + } + + public void invokeWorkflowForStatusUpdate(BulkPlanRequest bulkPlanRequest) { + ProcessInstanceRequest processInstanceRequest = createWorkflowRequest(bulkPlanRequest); + ProcessInstanceResponse processInstanceResponse = callWorkflowTransition(processInstanceRequest); + + enrichPlansPostTransition(processInstanceResponse, bulkPlanRequest); + } + + private void enrichPlansPostTransition(ProcessInstanceResponse processInstanceResponse, BulkPlanRequest bulkPlanRequest) { + // Update status and audit information post transition + bulkPlanRequest.getPlans().forEach(plan -> { + // Update status of plan + plan.setStatus(processInstanceResponse.getProcessInstances().get(0).getState().getState()); + + // Update audit information of plan + plan.setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails(plan.getAuditDetails(), bulkPlanRequest.getRequestInfo(), Boolean.FALSE)); + }); + } + + private ProcessInstanceRequest createWorkflowRequest(BulkPlanRequest bulkPlanRequest) { + List processInstanceList = new ArrayList<>(); + + // Perform auto assignment + List assignee = getAssigneeForAutoAssignment(bulkPlanRequest.getPlans().get(0), + bulkPlanRequest.getRequestInfo()); + + for(Plan plan: bulkPlanRequest.getPlans()) { + + // Setting assignee for send back actions + if (config.getWfSendBackActions().contains(plan.getWorkflow().getAction())) { + assignee = Collections.singletonList(plan.getAuditDetails().getLastModifiedBy()); + } + + // Set assignee + if(!ObjectUtils.isEmpty(assignee)) + plan.getWorkflow().setAssignes(assignee); + + plan.setAssignee(assignee); + + // Create process instance object from plan + ProcessInstance processInstance = ProcessInstance.builder() + .businessId(plan.getId()) + .tenantId(plan.getTenantId()) + .businessService(PLAN_ESTIMATION_BUSINESS_SERVICE) + .moduleName(MODULE_NAME_VALUE) + .action(plan.getWorkflow().getAction()) + .comment(plan.getWorkflow().getComments()) + .documents(plan.getWorkflow().getDocuments()) + .build(); + + // Enrich user list for process instance + enrichAssignesInProcessInstance(processInstance, plan.getWorkflow()); + + // Add entry for bulk transition + processInstanceList.add(processInstance); + } + + return ProcessInstanceRequest.builder() + .requestInfo(bulkPlanRequest.getRequestInfo()) + .processInstances(processInstanceList) + .build(); + } + + /** + * Creates a list of all the workflow states for the provided business service. + * @param requestInfo + * @param businessService + * @param tenantId + * @return + */ + public List getStatusFromBusinessService(RequestInfo requestInfo, String businessService, String tenantId) { + BusinessService businessServices = fetchBusinessService(requestInfo, businessService, tenantId); + + return businessServices.getStates().stream() + .map(State::getState) + .filter(state -> !ObjectUtils.isEmpty(state)) + .toList(); + } + + /** + * This method fetches business service details for the given tenant id and business service. + * + * @param requestInfo the request info from request. + * @param businessService businessService whose details are to be searched. + * @param tenantId tenantId from request. + * @return returns the business service response for the given tenant id and business service. + */ + public BusinessService fetchBusinessService(RequestInfo requestInfo, String businessService, String tenantId) { + + // Get business service uri + Map uriParameters = new HashMap<>(); + String uri = getBusinessServiceUri(businessService, tenantId, uriParameters); + + // Create request body + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); + BusinessServiceResponse businessServiceResponse = new BusinessServiceResponse(); + + try { + businessServiceResponse = restTemplate.postForObject(uri, requestInfoWrapper, BusinessServiceResponse.class, uriParameters); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BUSINESS_SERVICE_DETAILS, e); + } + + if (CollectionUtils.isEmpty(businessServiceResponse.getBusinessServices())) { + throw new CustomException(NO_BUSINESS_SERVICE_DATA_FOUND_CODE, NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE); + } + + return businessServiceResponse.getBusinessServices().get(0); + } + + /** + * This method creates business service uri with query parameters + * + * @param businessService businessService whose details are to be searched. + * @param tenantId tenant id from the request. + * @param uriParameters map that stores values corresponding to the placeholder in uri + * @return + */ + private String getBusinessServiceUri(String businessService, String tenantId, Map uriParameters) { + + StringBuilder uri = new StringBuilder(); + uri.append(config.getWfHost()).append(config.getBusinessServiceSearchEndpoint()).append(URI_BUSINESS_SERVICE_QUERY_TEMPLATE); + + uriParameters.put(URI_TENANT_ID_PARAM, tenantId); + uriParameters.put(URI_BUSINESS_SERVICE_PARAM, businessService); + + return uri.toString(); + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/util/BoundaryUtil.java b/health-services/plan-service/src/main/java/digit/util/BoundaryUtil.java new file mode 100644 index 00000000000..ec43e0f0447 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/BoundaryUtil.java @@ -0,0 +1,111 @@ +package digit.util; + +import digit.config.Configuration; +import digit.web.models.RequestInfoWrapper; +import digit.web.models.boundary.BoundarySearchResponse; +import digit.web.models.boundary.BoundaryTypeHierarchyResponse; +import digit.web.models.boundary.BoundaryTypeHierarchySearchCriteria; +import digit.web.models.boundary.BoundaryTypeHierarchySearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_BOUNDARY_DETAILS; +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS; + + +@Slf4j +@Component +public class BoundaryUtil { + + private RestTemplate restTemplate; + + private Configuration configs; + + public BoundaryUtil(RestTemplate restTemplate, Configuration configs) { + this.restTemplate = restTemplate; + this.configs = configs; + } + + /** + * This method fetches boundary relationships from Boundary service for the provided boundaryCode and hierarchyType. + * + * @param requestInfo request info from the request. + * @param boundaryCode boundary code from the request. + * @param tenantId tenant id from the request. + * @param hierarchyType hierarchy type from the request. + * @param includeParents is true if you want to include parent boundary. + * @param includeChildren is true if you want to include child boundary. + * @return returns the response from boundary service + */ + public BoundarySearchResponse fetchBoundaryData(RequestInfo requestInfo, String boundaryCode, String tenantId, String hierarchyType, Boolean includeParents, Boolean includeChildren) { + + // Create Boundary Relationship search uri + Map uriParameters = new HashMap<>(); + StringBuilder uri = getBoundaryRelationshipSearchUri(uriParameters, boundaryCode, tenantId, hierarchyType, includeParents, includeChildren); + + // Create request body + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); + BoundarySearchResponse boundarySearchResponse = new BoundarySearchResponse(); + + try { + boundarySearchResponse = restTemplate.postForObject(uri.toString(), requestInfoWrapper, BoundarySearchResponse.class, uriParameters); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BOUNDARY_DETAILS, e); + } + + return boundarySearchResponse; + } + + /** + * This method creates Boundary service uri with query parameters + * + * @param uriParameters map that stores values corresponding to the placeholder in uri + * @param boundaryCode boundary code from the request. + * @param tenantId tenant id from the request. + * @param hierarchyType hierarchy type from the request. + * @param includeParents is true if you want to include parent boundary. + * @param includeChildren is true if you want to include child boundary. + * @return a complete boundary service uri + */ + private StringBuilder getBoundaryRelationshipSearchUri(Map uriParameters, String boundaryCode, String tenantId, String hierarchyType, Boolean includeParents, Boolean includeChildren) { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getBoundaryServiceHost()).append(configs.getBoundaryRelationshipSearchEndpoint()).append("?codes={boundaryCode}&includeParents={includeParents}&includeChildren={includeChildren}&tenantId={tenantId}&hierarchyType={hierarchyType}"); + + uriParameters.put("boundaryCode", boundaryCode); + uriParameters.put("tenantId", tenantId); + uriParameters.put("includeParents", includeParents.toString()); + uriParameters.put("includeChildren", includeChildren.toString()); + uriParameters.put("hierarchyType", hierarchyType); + + return uri; + } + + public BoundaryTypeHierarchyResponse fetchBoundaryHierarchy(RequestInfo requestInfo, String tenantId, String hierarchyType) { + + // Create Boundary hierarchy search uri + String uri = getBoundaryHierarchySearchUri(); + + // Create request body + BoundaryTypeHierarchySearchCriteria searchCriteria = BoundaryTypeHierarchySearchCriteria.builder().tenantId(tenantId).hierarchyType(hierarchyType).build(); + BoundaryTypeHierarchySearchRequest searchRequest = BoundaryTypeHierarchySearchRequest.builder().requestInfo(requestInfo).boundaryTypeHierarchySearchCriteria(searchCriteria).build(); + BoundaryTypeHierarchyResponse searchResponse = new BoundaryTypeHierarchyResponse(); + + try { + searchResponse = restTemplate.postForObject(uri, searchRequest, BoundaryTypeHierarchyResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS, e); + } + + return searchResponse; + } + + private String getBoundaryHierarchySearchUri() { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getBoundaryServiceHost()).append(configs.getBoundaryHierarchySearchEndpoint()); + return uri.toString(); + } +} diff --git a/health-services/plan-service/src/main/java/digit/util/CampaignUtil.java b/health-services/plan-service/src/main/java/digit/util/CampaignUtil.java new file mode 100644 index 00000000000..5f1632e6366 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/CampaignUtil.java @@ -0,0 +1,91 @@ +package digit.util; + +import digit.config.Configuration; + +import digit.web.models.projectFactory.*; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class CampaignUtil { + + private RestTemplate restTemplate; + + private Configuration configs; + + public CampaignUtil(RestTemplate restTemplate, Configuration configs) { + this.restTemplate = restTemplate; + this.configs = configs; + } + + /** + * This method fetches data from project factory for provided campaignId and service boundaries + * + * @param requestInfo request info from the request + * @param campaignId campaign id provided in the request + * @param tenantId tenant id from the request + */ + public CampaignResponse fetchCampaignData(RequestInfo requestInfo, String campaignId, String tenantId) { + + // Build the URI for calling the Project Factory service + StringBuilder uri = buildCampaignSearchUri(); + + // Prepare the search request object with required campaign ID, tenant ID, and request information + CampaignSearchReq campaignSearchReq = getCampaignSearchRequest(requestInfo, campaignId, tenantId); + CampaignResponse campaignResponse = null; + + try { + campaignResponse = restTemplate.postForObject(uri.toString(), campaignSearchReq, CampaignResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_PROJECT_FACTORY, e); + } + + // Validate that the response contains campaign details, otherwise throw an exception + if (CollectionUtils.isEmpty(campaignResponse.getCampaignDetails())) { + throw new CustomException(NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE, NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE); + } + + return campaignResponse; + } + + /** + * This method create the uri for project factory to fetch campaign data. + * + * @return The complete URI. + */ + private StringBuilder buildCampaignSearchUri() { + return new StringBuilder().append(configs.getProjectFactoryHost()).append(configs.getProjectFactorySearchEndPoint()); + } + + /** + * Creates the request object for fetching campaign data. + * + * @param requestInfo Information about the request such as user details and correlation ID. + * @param campaignId The ID of the campaign to be searched. + * @param tenantId The tenant identifier (for multi-tenant support). + * @return The request object containing the search criteria and request info. + */ + private CampaignSearchReq getCampaignSearchRequest(RequestInfo requestInfo, String campaignId, String tenantId) { + Pagination pagination = Pagination.builder() + .limit(configs.getDefaultLimit()) + .offset(configs.getDefaultOffset()) + .build(); + + CampaignSearchCriteria searchCriteria = CampaignSearchCriteria.builder() + .ids(Collections.singletonList(campaignId)) + .tenantId(tenantId) + .pagination(pagination) + .build(); + + return CampaignSearchReq.builder().requestInfo(requestInfo).campaignSearchCriteria(searchCriteria).build(); + } +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/util/CensusUtil.java b/health-services/plan-service/src/main/java/digit/util/CensusUtil.java new file mode 100644 index 00000000000..fa45518c44a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/CensusUtil.java @@ -0,0 +1,60 @@ +package digit.util; + +import digit.config.Configuration; +import digit.web.models.census.CensusResponse; +import digit.web.models.census.CensusSearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class CensusUtil { + + private RestTemplate restTemplate; + + private Configuration config; + + public CensusUtil(RestTemplate restTemplate, Configuration config) { + this.restTemplate = restTemplate; + this.config = config; + } + + /** + * This method fetches data from Census based on the given census search request. + * + * @param searchRequest The census search request containing the search criteria. + * @return returns the census response. + */ + public CensusResponse fetchCensusRecords(CensusSearchRequest searchRequest) { + + // Get census search uri + String uri = getCensusUri().toString(); + + CensusResponse censusResponse = null; + try { + censusResponse = restTemplate.postForObject(uri, searchRequest, CensusResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_CENSUS, e); + } + + if (CollectionUtils.isEmpty(censusResponse.getCensus())) { + throw new CustomException(NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_CODE, NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_MESSAGE); + } + + return censusResponse; + } + + /** + * Builds the census search uri. + * + * @return returns the complete uri for census search. + */ + private StringBuilder getCensusUri() { + return new StringBuilder().append(config.getCensusHost()).append(config.getCensusSearchEndPoint()); + } +} diff --git a/health-services/plan-service/src/main/java/digit/util/CommonUtil.java b/health-services/plan-service/src/main/java/digit/util/CommonUtil.java new file mode 100644 index 00000000000..6635294fd87 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/CommonUtil.java @@ -0,0 +1,275 @@ +package digit.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.jayway.jsonpath.JsonPath; +import digit.repository.PlanConfigurationRepository; +import digit.web.models.Operation; +import digit.web.models.PlanConfiguration; +import digit.web.models.PlanConfigurationSearchCriteria; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.text.StringEscapeUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static digit.config.ServiceConstants.*; + +@Component +@Slf4j +public class CommonUtil { + + private PlanConfigurationRepository planConfigurationRepository; + + private ObjectMapper objectMapper; + + public CommonUtil(PlanConfigurationRepository planConfigurationRepository, ObjectMapper objectMapper) { + this.planConfigurationRepository = planConfigurationRepository; + this.objectMapper = objectMapper; + } + + /** + * Validates the given input string against the provided regex pattern. + * + * @param patternString the regex pattern to validate against + * @param inputString the input string to be validated + * @return true if the input string matches the regex pattern, false otherwise + */ + public Boolean validateStringAgainstRegex(String patternString, String inputString) { + Pattern pattern = Pattern.compile(patternString); + Matcher matcher = pattern.matcher(inputString); + return matcher.matches(); + } + + + /** + * Extracts provided field from the additional details object + * + * @param additionalDetails the additionalDetails object from PlanConfigurationRequest + * @param fieldToExtract the name of the field to be extracted from the additional details + * @return the value of the specified field as a string + * @throws CustomException if the field does not exist + */ + public Object extractFieldsFromJsonObject(Object additionalDetails, String fieldToExtract) { + try { + String jsonString = objectMapper.writeValueAsString(additionalDetails); + JsonNode rootNode = objectMapper.readTree(jsonString); + + JsonNode node = rootNode.get(fieldToExtract); + if (node != null && !node.isNull()) { + + // Check for different types of JSON nodes + if (node.isDouble() || node.isFloat()) { + return BigDecimal.valueOf(node.asDouble()); // Convert Double to BigDecimal + } else if (node.isLong() || node.isInt()) { + return BigDecimal.valueOf(node.asLong()); // Convert Long to BigDecimal + } else if (node.isBoolean()) { + return node.asBoolean(); + } else if (node.isTextual()) { + return node.asText(); + } + } + return null; + } catch (Exception e) { + log.error(e.getMessage() + fieldToExtract); + throw new CustomException(PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE, PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE + fieldToExtract); + } + } + + /** + * Extracts provided field from the additional details object + * + * @param additionalDetails the additionalDetails object from PlanConfigurationRequest + * @param fieldToExtract the name of the field to be extracted from the additional details + * @return the value of the specified field as a list of string + * @throws CustomException if the field does not exist + */ + public List extractFieldsFromJsonObject(Object additionalDetails, String fieldToExtract, Class valueType) { + try { + String jsonString = objectMapper.writeValueAsString(additionalDetails); + JsonNode rootNode = objectMapper.readTree(jsonString); + + JsonNode node = rootNode.get(fieldToExtract); + List list = new ArrayList<>(); + if (node != null && node.isArray()) { + for (JsonNode idNode : node) { + list.add(idNode.asText()); + } + } + return list; + } catch (Exception e) { + log.error(e.getMessage() + fieldToExtract); + throw new CustomException(PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE, PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE + fieldToExtract); + } + } + + /** + * Constructs a JSONPath expression used to filter assumptions based on the given parameters - + * campaign type, distribution process, registration process, resource distribution strategy, + * and whether registration and distribution are together match the provided values. + * + * @param campaignType The type of campaign to filter by (e.g., "Health", "Education"). + * @param distributionProcess The process of distribution to filter by (e.g., "Central", "Decentralized"). + * @param registrationProcess The registration process to filter by (e.g., "Online", "In-Person"). + * @param resourceDistributionStrategyCode The strategy code for resource distribution to filter by (e.g., "Strategy1"). + * @param isRegistrationAndDistributionTogether Whether registration and distribution are combined, to filter by ("true"/"false"). + * @return A JSONPath expression string that filters assumptions based on the given criteria. + */ + public String createJsonPathForAssumption( + String campaignType, + String distributionProcess, + String registrationProcess, + String resourceDistributionStrategyCode, + String isRegistrationAndDistributionTogether + ) { + + StringBuilder jsonPathFilters = new StringBuilder(JSONPATH_FILTER_PREFIX); + jsonPathFilters.append(JSON_PATH_FILTER_CAMPAIGN_TYPE).append(EQUALS).append(SINGLE_QUOTE).append(StringEscapeUtils.escapeJson(campaignType)).append(SINGLE_QUOTE) + .append(AND).append(JSON_PATH_FILTER_DISTRIBUTION_PROCESS).append(EQUALS).append(SINGLE_QUOTE).append(StringEscapeUtils.escapeJson(distributionProcess)).append(SINGLE_QUOTE) + .append(AND).append(JSON_PATH_FILTER_REGISTRATION_PROCESS).append(EQUALS).append(SINGLE_QUOTE).append(StringEscapeUtils.escapeJson(registrationProcess)).append(SINGLE_QUOTE) + .append(AND).append(JSON_PATH_FILTER_RESOURCE_DISTRIBUTION_STRATEGY_CODE).append(EQUALS).append(SINGLE_QUOTE).append(StringEscapeUtils.escapeJson(resourceDistributionStrategyCode)).append(SINGLE_QUOTE) + .append(AND).append(JSON_PATH_FILTER_IS_REGISTRATION_AND_DISTRIBUTION_TOGETHER).append(EQUALS).append(SINGLE_QUOTE).append(StringEscapeUtils.escapeJson(isRegistrationAndDistributionTogether)).append(SINGLE_QUOTE) + .append(JSONPATH_FILTER_SUFFIX); + + return JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_ASSUMPTION + jsonPathFilters + FILTER_ALL_ASSUMPTIONS; + } + + + /** + * Searches the plan config based on the plan config id provided + * + * @param planConfigId the plan config id to validate + * @param tenantId the tenant id of the plan config + * @return list of planConfiguration for the provided plan config id + */ + public List searchPlanConfigId(String planConfigId, String tenantId) { + List planConfigurations = planConfigurationRepository.search(PlanConfigurationSearchCriteria.builder() + .id(planConfigId) + .tenantId(tenantId) + .build()); + + return planConfigurations; + } + + /** + * This method returns the planConfigName for the provided planConfig id + * + * @param tenantId + * @param planConfigId + */ + public String getPlanConfigName(String tenantId, String planConfigId) { + + List planConfigsFromSearch = searchPlanConfigId(planConfigId, tenantId); + return planConfigsFromSearch.get(0).getName(); + } + + /** + * Validates the user information within the provided PlanConfigurationRequest. + * + * @param requestInfo the request info containing the user information to be validated + * @throws CustomException if the user information is missing in the request + */ + public void validateUserInfo(RequestInfo requestInfo) + { + if (ObjectUtils.isEmpty(requestInfo.getUserInfo())) { + log.error(USERINFO_MISSING_MESSAGE); + throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); + } + } + + /** + * This is a helper method to get the lowest and highest hierarchy for microplan from MDMS + * + * @param mdmsData the mdms data + * @return returns the lowest and highest hierarchy for microplan + */ + public Map getMicroplanHierarchy(Object mdmsData) { + + String jsonPathForMicroplanHierarchy = JSON_ROOT_PATH + MDMS_ADMIN_CONSOLE_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_HIERARCHY_SCHEMA + HIERARCHY_CONFIG_FOR_MICROPLAN; + + List> hierarchyForMicroplan; + + try { + log.info(jsonPathForMicroplanHierarchy); + hierarchyForMicroplan = JsonPath.read(mdmsData, jsonPathForMicroplanHierarchy); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); + } + + Map hierarchyMap = new HashMap<>(); + hierarchyMap.put(LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN, hierarchyForMicroplan.get(0).get(LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN).toString().toLowerCase()); + hierarchyMap.put(HIGHEST_HIERARCHY_FIELD_FOR_MICROPLAN, hierarchyForMicroplan.get(0).get(HIGHEST_HIERARCHY_FIELD_FOR_MICROPLAN).toString().toLowerCase()); + + return hierarchyMap; + } + + /** + * Checks if the setup process is completed based on the workflow action in the plan configuration. + * + * @param planConfiguration The plan configuration to check. + * @return true if the setup is completed, otherwise false. + */ + public boolean isSetupCompleted(PlanConfiguration planConfiguration) { + if(!ObjectUtils.isEmpty(planConfiguration.getWorkflow())) + return Objects.equals(planConfiguration.getWorkflow().getAction(), SETUP_COMPLETED_ACTION); + + return false; + } + + /** + * Checks if the setup process is completed based on the workflow action in the plan configuration. + * + * @param planConfiguration The plan configuration to check. + * @return true if the setup is completed, otherwise false. + */ + public boolean checkForEmptyOperationsOrAssumptions(PlanConfiguration planConfiguration) { + return !ObjectUtils.isEmpty(planConfiguration.getOperations()) && !ObjectUtils.isEmpty(planConfiguration.getAssumptions()); + } + + + /** + * Adds or updates the provided fields in the additional details object. + * + * @param additionalDetails the additional details object to be updated. + * @param fieldsToBeUpdated map of field to be updated and it's updated value. + * @return returns the updated additional details object. + */ + + public Map updateFieldInAdditionalDetails(Object additionalDetails, Map fieldsToBeUpdated) { + try { + + // Get or create the additionalDetails as an ObjectNode + ObjectNode objectNode = (additionalDetails == null || additionalDetails instanceof NullNode) + ? objectMapper.createObjectNode() + : objectMapper.convertValue(additionalDetails, ObjectNode.class); + + // Update or add the field in additional details object + fieldsToBeUpdated.forEach((key, value) -> objectNode.set(key, objectMapper.valueToTree(value))); + + // Convert updated ObjectNode back to a Map + return objectMapper.convertValue(objectNode, Map.class); + + } catch (Exception e) { + throw new CustomException(ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE, ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE + e); + } + } + + public void sortOperationsByExecutionOrder(List planConfigurations) { + for (PlanConfiguration planConfiguration : planConfigurations) { + List operations = planConfiguration.getOperations(); + if (!ObjectUtils.isEmpty(operations)) { + operations.sort(Comparator.comparing(Operation::getExecutionOrder)); + } + } + } + +} diff --git a/health-services/plan-service/src/main/java/digit/util/FacilityUtil.java b/health-services/plan-service/src/main/java/digit/util/FacilityUtil.java new file mode 100644 index 00000000000..025d4ea6bb6 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/FacilityUtil.java @@ -0,0 +1,84 @@ +package digit.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.config.Configuration; +import digit.web.models.PlanFacilityRequest; +import digit.web.models.facility.FacilityResponse; +import digit.web.models.facility.FacilitySearchCriteria; +import digit.web.models.facility.FacilitySearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_FACILITY; + +@Slf4j +@Component +public class FacilityUtil { + + private RestTemplate restTemplate; + private Configuration configs; + private ObjectMapper mapper; + + public FacilityUtil(RestTemplate restTemplate, Configuration configs, ObjectMapper mapper) { + this.restTemplate = restTemplate; + this.configs = configs; + this.mapper = mapper; + } + + public FacilityResponse fetchFacilityData(PlanFacilityRequest planFacilityRequest) { + String baseUri = configs.getFacilityHost()+ configs.getFacilitySearchEndPoint(); + + // Retrieve tenantId from planFacilityRequest + String tenantId = planFacilityRequest.getPlanFacility().getTenantId(); + + // Retrieve the limit and offset from the configuration + int limit = configs.getDefaultLimit(); + int offset = configs.getDefaultOffset(); + + // Use UriComponentsBuilder to construct the URI with query parameters + String uri = UriComponentsBuilder.fromHttpUrl(baseUri) + .queryParam("tenantId", tenantId) + .queryParam("limit", limit) + .queryParam("offset", offset) + .toUriString(); + + FacilitySearchRequest facilitySearchRequest = getFacilitySearchRequest(planFacilityRequest); + FacilityResponse facilityResponse = new FacilityResponse(); + Object response = new HashMap<>(); + try { + // Use postForObject to send the request with the URI containing query params + response = restTemplate.postForObject(uri, facilitySearchRequest, Map.class); + facilityResponse = mapper.convertValue(response , FacilityResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_FACILITY, e); + } + log.info(facilityResponse.toString()); + return facilityResponse; + } + + private FacilitySearchRequest getFacilitySearchRequest(PlanFacilityRequest planFacilityRequest) { + // Retrieve facilityId,requestInfo from planFacilityRequest + String facilityId = planFacilityRequest.getPlanFacility().getFacilityId(); + RequestInfo requestInfo = planFacilityRequest.getRequestInfo(); + + FacilitySearchCriteria searchCriteria = FacilitySearchCriteria.builder() + .id(Collections.singletonList(facilityId)) + .build(); + + return FacilitySearchRequest.builder() + .requestInfo(requestInfo) + .facilitySearchCriteria(searchCriteria) + .build(); + } + + + +} diff --git a/health-services/plan-service/src/main/java/digit/util/MdmsUtil.java b/health-services/plan-service/src/main/java/digit/util/MdmsUtil.java index 4e301a3e5f5..a4979c5da52 100644 --- a/health-services/plan-service/src/main/java/digit/util/MdmsUtil.java +++ b/health-services/plan-service/src/main/java/digit/util/MdmsUtil.java @@ -2,7 +2,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import digit.config.Configuration; + import java.util.LinkedList; + import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.mdms.model.*; @@ -38,11 +40,11 @@ public Object fetchMdmsData(RequestInfo requestInfo, String tenantId) { StringBuilder uri = new StringBuilder(); uri.append(configs.getMdmsHost()).append(configs.getMdmsEndPoint()); MdmsCriteriaReq mdmsCriteriaReq = getMdmsRequest(requestInfo, tenantId); - Object mdmsResponseMap = new HashMap<>(); + Object mdmsResponseMap = new HashMap<>(); MdmsResponse mdmsResponse = new MdmsResponse(); try { - mdmsResponseMap = restTemplate.postForObject(uri.toString(), mdmsCriteriaReq, Map.class); - mdmsResponse = mapper.convertValue(mdmsResponseMap , MdmsResponse.class); + mdmsResponseMap = restTemplate.postForObject(uri.toString(), mdmsCriteriaReq, Map.class); + mdmsResponse = mapper.convertValue(mdmsResponseMap, MdmsResponse.class); } catch (Exception e) { log.error(ERROR_WHILE_FETCHING_FROM_MDMS, e); } @@ -55,18 +57,42 @@ public Object fetchMdmsData(RequestInfo requestInfo, String tenantId) { return result; } + /** + * This method constructs the criteria request for MDMS Api call + * + * @param requestInfo requestInfo from the provided request + * @param tenantId tenant id from the provided request + * @return Returns the mdms criteria request + */ public MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId) { ModuleDetail assumptionModuleDetail = getPlanModuleDetail(); + ModuleDetail adminConsoleModuleDetail = getAdminConsoleModuleDetail(); List moduleDetails = new LinkedList<>(); moduleDetails.add(assumptionModuleDetail); + moduleDetails.add(adminConsoleModuleDetail); MdmsCriteria mdmsCriteria = MdmsCriteria.builder().moduleDetails(moduleDetails).tenantId(tenantId).build(); return MdmsCriteriaReq.builder().mdmsCriteria(mdmsCriteria).requestInfo(requestInfo).build(); } + private ModuleDetail getAdminConsoleModuleDetail() { + List adminConsoleMasters = new ArrayList<>(); + + MasterDetail hierarchyConfigMaster = MasterDetail.builder().name(MDMS_MASTER_HIERARCHY_SCHEMA).build(); + + adminConsoleMasters.add(hierarchyConfigMaster); + + return ModuleDetail.builder().masterDetails(adminConsoleMasters).moduleName(MDMS_ADMIN_CONSOLE_MODULE_NAME).build(); + } + + /** + * This method constructs module detail object for 'hcm-microplanning' module + * + * @return Returns the module details for 'hcm-microplanning' module + */ private ModuleDetail getPlanModuleDetail() { List assumptionMasterDetails = new ArrayList<>(); @@ -75,14 +101,16 @@ private ModuleDetail getPlanModuleDetail() { MasterDetail ruleConfigureInputsMasterDetail = MasterDetail.builder().name(MDMS_MASTER_RULE_CONFIGURE_INPUTS).filter(FILTER_DATA).build(); MasterDetail schemaDetails = MasterDetail.builder().name(MDMS_MASTER_SCHEMAS).build(); MasterDetail metricDetails = MasterDetail.builder().name(MDMS_MASTER_METRIC).build(); - MasterDetail UnitDetails = MasterDetail.builder().name(MDMS_MASTER_UOM).build(); + MasterDetail unitDetails = MasterDetail.builder().name(MDMS_MASTER_UOM).build(); + MasterDetail namingRegexDetails = MasterDetail.builder().name(MDMS_MASTER_NAME_VALIDATION).build(); assumptionMasterDetails.add(assumptionMasterDetail); assumptionMasterDetails.add(uploadConfigMasterDetail); assumptionMasterDetails.add(ruleConfigureInputsMasterDetail); assumptionMasterDetails.add(schemaDetails); assumptionMasterDetails.add(metricDetails); - assumptionMasterDetails.add(UnitDetails); + assumptionMasterDetails.add(unitDetails); + assumptionMasterDetails.add(namingRegexDetails); return ModuleDetail.builder().masterDetails(assumptionMasterDetails).moduleName(MDMS_PLAN_MODULE_NAME).build(); } diff --git a/health-services/plan-service/src/main/java/digit/util/MdmsV2Util.java b/health-services/plan-service/src/main/java/digit/util/MdmsV2Util.java new file mode 100644 index 00000000000..dad22d39d35 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/MdmsV2Util.java @@ -0,0 +1,76 @@ +package digit.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.config.Configuration; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; +import digit.web.models.mdmsV2.*; + +import java.util.*; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class MdmsV2Util { + + private RestTemplate restTemplate; + + private ObjectMapper objectMapper; + + private Configuration configs; + + public MdmsV2Util(RestTemplate restTemplate, ObjectMapper objectMapper, Configuration configs) + { + this.restTemplate = restTemplate; + this.objectMapper = objectMapper; + this.configs = configs; + } + + public List fetchMdmsV2Data(RequestInfo requestInfo, String tenantId, String schemaCode, String uniqueIdentifier) + { + StringBuilder uri = getMdmsV2Uri(); + MdmsCriteriaReqV2 mdmsCriteriaReqV2 = getMdmsV2Request(requestInfo, tenantId, schemaCode, uniqueIdentifier); + MdmsResponseV2 mdmsResponseV2 = null; + try { + mdmsResponseV2 = restTemplate.postForObject(uri.toString(), mdmsCriteriaReqV2, MdmsResponseV2.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_MDMS, e); + } + + if(ObjectUtils.isEmpty(mdmsResponseV2.getMdms())) + { + log.error(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE + " - " + tenantId); + throw new CustomException(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE, NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE); + } + + return mdmsResponseV2.getMdms(); + } + + private StringBuilder getMdmsV2Uri() + { + StringBuilder uri = new StringBuilder(); + return uri.append(configs.getMdmsHost()).append(configs.getMdmsV2EndPoint()); + } + + private MdmsCriteriaReqV2 getMdmsV2Request(RequestInfo requestInfo, String tenantId, String schemaCode, String uniqueIdentifier) + { + MdmsCriteriaV2 mdmsCriteriaV2 = MdmsCriteriaV2.builder() + .tenantId(tenantId) + .schemaCode(schemaCode) + .limit(configs.getDefaultLimit()) + .offset(configs.getDefaultOffset()).build(); + + if(!ObjectUtils.isEmpty(uniqueIdentifier)) + mdmsCriteriaV2.setUniqueIdentifiers(Collections.singletonList(uniqueIdentifier)); + + return MdmsCriteriaReqV2.builder() + .requestInfo(requestInfo) + .mdmsCriteriaV2(mdmsCriteriaV2).build(); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/util/QueryUtil.java b/health-services/plan-service/src/main/java/digit/util/QueryUtil.java index 84817b60870..070f442a897 100644 --- a/health-services/plan-service/src/main/java/digit/util/QueryUtil.java +++ b/health-services/plan-service/src/main/java/digit/util/QueryUtil.java @@ -1,7 +1,15 @@ package digit.util; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; +import digit.config.Configuration; +import org.egov.tracer.model.CustomException; +import org.postgresql.util.PGobject; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -11,10 +19,17 @@ import static digit.config.ServiceConstants.DOT_REGEX; import static digit.config.ServiceConstants.DOT_SEPARATOR; - +@Component public class QueryUtil { - private QueryUtil(){} + private Configuration config; + + private ObjectMapper objectMapper; + + private QueryUtil(Configuration config, ObjectMapper objectMapper) { + this.config = config; + this.objectMapper = objectMapper; + } private static final Gson gson = new Gson(); @@ -22,13 +37,14 @@ private QueryUtil(){} * This method aids in adding "WHERE" clause and "AND" condition depending on preparedStatementList i.e., * if preparedStatementList is empty, it will understand that it is the first clause being added so it * will add "WHERE" to the query and otherwise it will + * * @param query * @param preparedStmtList */ - public static void addClauseIfRequired(StringBuilder query, List preparedStmtList){ - if(preparedStmtList.isEmpty()){ + public void addClauseIfRequired(StringBuilder query, List preparedStmtList) { + if (preparedStmtList.isEmpty()) { query.append(" WHERE "); - }else{ + } else { query.append(" AND "); } } @@ -36,10 +52,11 @@ public static void addClauseIfRequired(StringBuilder query, List prepare /** * This method returns a string with placeholders equal to the number of values that need to be put inside * "IN" clause + * * @param size * @return */ - public static String createQuery(Integer size) { + public String createQuery(Integer size) { StringBuilder builder = new StringBuilder(); IntStream.range(0, size).forEach(i -> { @@ -53,40 +70,48 @@ public static String createQuery(Integer size) { /** * This method adds a set of String values into preparedStatementList + * * @param preparedStmtList * @param ids */ - public static void addToPreparedStatement(List preparedStmtList, Set ids) { + public void addToPreparedStatement(List preparedStmtList, Set ids) { ids.forEach(id -> { preparedStmtList.add(id); }); } + public void addToPreparedStatement(List preparedStmtList, List ids) { + ids.forEach(id -> { + preparedStmtList.add(id); + }); + } /** * This method appends order by clause to the query + * * @param query * @param orderByClause * @return */ - public static String addOrderByClause(String query, String orderByClause){ + public String addOrderByClause(String query, String orderByClause) { return query + orderByClause; } /** * This method prepares partial json string from the filter map to query on jsonb column + * * @param filterMap * @return */ - public static String preparePartialJsonStringFromFilterMap(Map filterMap) { + public String preparePartialJsonStringFromFilterMap(Map filterMap) { Map queryMap = new HashMap<>(); filterMap.keySet().forEach(key -> { - if(key.contains(DOT_SEPARATOR)){ + if (key.contains(DOT_SEPARATOR)) { String[] keyArray = key.split(DOT_REGEX); Map nestedQueryMap = new HashMap<>(); prepareNestedQueryMap(0, keyArray, nestedQueryMap, filterMap.get(key)); queryMap.put(keyArray[0], nestedQueryMap.get(keyArray[0])); - } else{ + } else { queryMap.put(key, filterMap.get(key)); } }); @@ -100,14 +125,15 @@ public static String preparePartialJsonStringFromFilterMap(Map f * Tail recursive method to prepare n-level nested partial json for queries on nested data in * master data. For e.g. , if the key is in the format a.b.c, it will construct a nested json * object of the form - {"a":{"b":{"c": "value"}}} + * * @param index * @param nestedKeyArray * @param currentQueryMap * @param value */ - private static void prepareNestedQueryMap(int index, String[] nestedKeyArray, Map currentQueryMap, String value) { + private void prepareNestedQueryMap(int index, String[] nestedKeyArray, Map currentQueryMap, String value) { // Return when all levels have been reached. - if(index == nestedKeyArray.length) + if (index == nestedKeyArray.length) return; // For the final level simply put the value in the map. @@ -123,4 +149,43 @@ else if (index == nestedKeyArray.length - 1) { prepareNestedQueryMap(index + 1, nestedKeyArray, (Map) currentQueryMap.get(nestedKeyArray[index]), value); } + /** + * This method adds pagination to the query + * + * @param query + * @param preparedStmtList + * @return + */ + public String getPaginatedQuery(String query, List preparedStmtList) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(config.getDefaultOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(config.getDefaultLimit()); + + return paginatedQuery.toString(); + } + + /** + * This method is used to extract and parse JSON data into a JsonNode object + * + * @param pGobject postgreSQL specific object + * @return returns a JsonNode + */ + public JsonNode getAdditionalDetail(PGobject pGobject) { + JsonNode additionalDetail = null; + + try { + if (!ObjectUtils.isEmpty(pGobject)) { + additionalDetail = objectMapper.readTree(pGobject.getValue()); + } + } catch (IOException e) { + throw new CustomException("PARSING_ERROR", "Failed to parse additionalDetails object"); + } + return additionalDetail; + } } diff --git a/health-services/plan-service/src/main/java/digit/util/ServiceUtil.java b/health-services/plan-service/src/main/java/digit/util/ServiceUtil.java new file mode 100644 index 00000000000..19c7bebeea7 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/ServiceUtil.java @@ -0,0 +1,12 @@ +package digit.util; + +import org.springframework.stereotype.Component; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Component +public class ServiceUtil { + + +} diff --git a/health-services/plan-service/src/main/java/digit/util/UserUtil.java b/health-services/plan-service/src/main/java/digit/util/UserUtil.java new file mode 100644 index 00000000000..0e60073313e --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/UserUtil.java @@ -0,0 +1,73 @@ +package digit.util; + +import digit.config.Configuration; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.user.UserDetailResponse; +import org.egov.common.contract.user.UserSearchRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; + +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_USER_SERVICE; + +@Slf4j +@Component +public class UserUtil { + + private Configuration config; + + private RestTemplate restTemplate; + + public UserUtil(RestTemplate restTemplate, Configuration config) { + this.restTemplate = restTemplate; + this.config = config; + } + + /** + * This method fetches user details from User Service for the provided search request + * + * @param userSearchReq Search request to search for user detail response + */ + public UserDetailResponse fetchUserDetail(UserSearchRequest userSearchReq) { + + UserDetailResponse userDetailResponse = new UserDetailResponse(); + + try { + userDetailResponse = restTemplate.postForObject(getUserServiceUri().toString(), userSearchReq, UserDetailResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_USER_SERVICE, e); + } + + return userDetailResponse; + } + + /** + * This method creates the uri for User service + * + * @return uri for user detail search + */ + private StringBuilder getUserServiceUri() { + return new StringBuilder().append(config.getUserServiceHost()).append(config.getUserSearchEndPoint()); + } + + /** + * This method creates the search request body for user detail search + * + * @param requestInfo Request Info from the request body + * @param employeeId Employee id for the provided plan employee assignment request + * @param tenantId Tenant id from the plan employee assignment request + * @return Search request body for user detail search + */ + public UserSearchRequest getUserSearchReq(RequestInfo requestInfo, String employeeId, String tenantId) { + + UserSearchRequest userSearchRequest = new UserSearchRequest(); + + userSearchRequest.setRequestInfo(requestInfo); + userSearchRequest.setTenantId(tenantId); + userSearchRequest.setUuid(Collections.singletonList(employeeId)); + + return userSearchRequest; + } +} diff --git a/health-services/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java b/health-services/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java index 1577ce3dbb1..d50610832e9 100644 --- a/health-services/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java +++ b/health-services/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java @@ -3,7 +3,6 @@ import digit.service.PlanConfigurationService; import digit.util.ResponseInfoFactory; -import digit.web.models.PlanConfiguration; import digit.web.models.PlanConfigurationRequest; import digit.web.models.PlanConfigurationResponse; import digit.web.models.PlanConfigurationSearchRequest; @@ -45,13 +44,7 @@ public PlanConfigController(ObjectMapper objectMapper, PlanConfigurationService @RequestMapping(value = "/config/_create", method = RequestMethod.POST) public ResponseEntity configCreatePost(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody PlanConfigurationRequest body) { - PlanConfigurationRequest planConfigurationRequest = planConfigurationService.create(body); - PlanConfigurationResponse response = PlanConfigurationResponse.builder() - .planConfiguration(Collections.singletonList(planConfigurationRequest.getPlanConfiguration())) - .responseInfo(responseInfoFactory - .createResponseInfoFromRequestInfo(body.getRequestInfo(), true)) - .build(); - + PlanConfigurationResponse response = planConfigurationService.create(body); return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); } diff --git a/health-services/plan-service/src/main/java/digit/web/controllers/PlanController.java b/health-services/plan-service/src/main/java/digit/web/controllers/PlanController.java index 2381b009d40..43f50e6a5af 100644 --- a/health-services/plan-service/src/main/java/digit/web/controllers/PlanController.java +++ b/health-services/plan-service/src/main/java/digit/web/controllers/PlanController.java @@ -30,7 +30,7 @@ public PlanController(PlanService planService) { * @return */ @RequestMapping(value = "/_create", method = RequestMethod.POST) - public ResponseEntity createPost(@Valid @RequestBody PlanRequest body) { + public ResponseEntity create(@Valid @RequestBody PlanRequest body) { PlanResponse planResponse = planService.createPlan(body); return ResponseEntity.status(HttpStatus.ACCEPTED).body(planResponse); } @@ -41,7 +41,7 @@ public ResponseEntity createPost(@Valid @RequestBody PlanRequest b * @return */ @RequestMapping(value = "/_search", method = RequestMethod.POST) - public ResponseEntity searchPost(@Valid @RequestBody PlanSearchRequest body) { + public ResponseEntity search(@Valid @RequestBody PlanSearchRequest body) { PlanResponse planResponse = planService.searchPlan(body); return ResponseEntity.status(HttpStatus.OK).body(planResponse); } @@ -52,9 +52,20 @@ public ResponseEntity searchPost(@Valid @RequestBody PlanSearchReq * @return */ @RequestMapping(value = "/_update", method = RequestMethod.POST) - public ResponseEntity updatePost(@Valid @RequestBody PlanRequest body) { + public ResponseEntity update(@Valid @RequestBody PlanRequest body) { PlanResponse planResponse = planService.updatePlan(body); return ResponseEntity.status(HttpStatus.ACCEPTED).body(planResponse); } + /** + * Request handler for serving bulk plan update requests + * @param body + * @return + */ + @RequestMapping(value = "/bulk/_update", method = RequestMethod.POST) + public ResponseEntity bulkUpdate(@Valid @RequestBody BulkPlanRequest body) { + PlanResponse planResponse = planService.bulkUpdate(body); + return ResponseEntity.status(HttpStatus.CREATED).body(planResponse); + } + } diff --git a/health-services/plan-service/src/main/java/digit/web/controllers/PlanEmployeeController.java b/health-services/plan-service/src/main/java/digit/web/controllers/PlanEmployeeController.java new file mode 100644 index 00000000000..db707f9e872 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/controllers/PlanEmployeeController.java @@ -0,0 +1,62 @@ +package digit.web.controllers; + +import digit.service.PlanEmployeeService; +import digit.web.models.*; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@Controller +public class PlanEmployeeController { + + PlanEmployeeService planEmployeeService; + + public PlanEmployeeController(PlanEmployeeService planEmployeeService) + { + this.planEmployeeService = planEmployeeService; + } + + /** + * Request handler for serving plan employee assignment create requests + * @param body + * @return + */ + @RequestMapping(value = "/employee/_create", method = RequestMethod.POST) + public ResponseEntity employeeCreatePost(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody PlanEmployeeAssignmentRequest body) { + + PlanEmployeeAssignmentResponse response = planEmployeeService.create(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + /** + * Request handler for serving plan employee assignment search requests + * @param body + * @return + */ + @RequestMapping(value = "/employee/_search", method = RequestMethod.POST) + public ResponseEntity employeeSearchPost(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody PlanEmployeeAssignmentSearchRequest body) { + + PlanEmployeeAssignmentResponse response = planEmployeeService.search(body); + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * Request handler for serving plan employee assignment update requests + * @param body + * @return + */ + @RequestMapping(value = "/employee/_update", method = RequestMethod.POST) + public ResponseEntity employeeUpdatePost(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody PlanEmployeeAssignmentRequest body) { + + PlanEmployeeAssignmentResponse response = planEmployeeService.update(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } +} diff --git a/health-services/plan-service/src/main/java/digit/web/controllers/PlanFacilityController.java b/health-services/plan-service/src/main/java/digit/web/controllers/PlanFacilityController.java new file mode 100644 index 00000000000..bca90f5c544 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/controllers/PlanFacilityController.java @@ -0,0 +1,61 @@ +package digit.web.controllers; + +import digit.service.PlanFacilityService; +import digit.web.models.*; +import jakarta.validation.Valid; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@Validated +@Controller +@RequestMapping("plan") +public class PlanFacilityController { + + private PlanFacilityService planFacilityService; + + public PlanFacilityController(PlanFacilityService planFacilityService) { + this.planFacilityService = planFacilityService; + } + + /** + * Request handler for serving plan facility create requests + * + * @param planFacilityRequest + * @return + */ + @RequestMapping(value = "/facility/_create", method = RequestMethod.POST) + public ResponseEntity createPlanFacility(@Valid @RequestBody PlanFacilityRequest planFacilityRequest) { + PlanFacilityResponse planFacilityResponse = planFacilityService.createPlanFacility(planFacilityRequest); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(planFacilityResponse); + } + + /** + * Request handler for serving plan facility search requests + * + * @param planFacilityRequest + * @return + */ + @RequestMapping(value = "/facility/_search", method = RequestMethod.POST) + public ResponseEntity searchPlanFacility(@Valid @RequestBody PlanFacilitySearchRequest planFacilityRequest) { + PlanFacilityResponse planFacilityResponse = planFacilityService.searchPlanFacility(planFacilityRequest); + return ResponseEntity.status(HttpStatus.OK).body(planFacilityResponse); + } + + /** + * Request handler for serving plan facility update requests + * + * @param planFacilityRequest + * @return + */ + @RequestMapping(value = "/facility/_update", method = RequestMethod.POST) + public ResponseEntity updatePlanFacility(@Valid @RequestBody PlanFacilityRequest planFacilityRequest) { + PlanFacilityResponse planFacilityResponse = planFacilityService.updatePlanFacility(planFacilityRequest); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(planFacilityResponse); + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/Assumption.java b/health-services/plan-service/src/main/java/digit/web/models/Assumption.java index a4b7e3ad01f..81486894093 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/Assumption.java +++ b/health-services/plan-service/src/main/java/digit/web/models/Assumption.java @@ -38,10 +38,19 @@ public class Assumption { @NotNull @Valid @DecimalMin(value = "0.01", inclusive = true, message = "The Assumption value must be greater than 0") - @DecimalMax(value = "9999999999.99", inclusive = true, message = "The assumption value must not exceed 10 digits in total, including up to 2 decimal places.") - @Digits(integer = 10, fraction = 2, message = "The Assumption value must have up to 10 digits and up to 2 decimal points") + @DecimalMax(value = "1000.00", inclusive = true, message = "The assumption value must not exceed 4 digits in total, including up to 2 decimal places.") + @Digits(integer = 4, fraction = 2, message = "The Assumption value must have up to 10 digits and up to 2 decimal points") private BigDecimal value = null; + @JsonProperty("source") + @NotNull(message = "Source cannot be null. Please specify a valid source.") + private Source source = null; + + @JsonProperty("category") + @NotNull + @Size(min = 2, max = 64) + private String category = null; + @JsonProperty("active") @NotNull private Boolean active = true; diff --git a/health-services/plan-service/src/main/java/digit/web/models/BulkPlanRequest.java b/health-services/plan-service/src/main/java/digit/web/models/BulkPlanRequest.java new file mode 100644 index 00000000000..f12bbc1ee8f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/BulkPlanRequest.java @@ -0,0 +1,33 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +import java.util.List; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BulkPlanRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Plans") + @Valid + @NotNull + @NotEmpty + private List plans = null; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/File.java b/health-services/plan-service/src/main/java/digit/web/models/File.java index 68cf28cd46b..3b232a60aeb 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/File.java +++ b/health-services/plan-service/src/main/java/digit/web/models/File.java @@ -14,6 +14,8 @@ import lombok.Data; import lombok.Builder; +import java.util.Arrays; + /** * File */ @@ -72,12 +74,10 @@ public String toString() { @JsonCreator public static InputFileTypeEnum fromValue(String text) { - for (InputFileTypeEnum b : InputFileTypeEnum.values()) { - if (String.valueOf(b.value).equals(text)) { - return b; - } - } - return null; + return Arrays.stream(InputFileTypeEnum.values()) + .filter(b -> String.valueOf(b.value).equals(text)) + .findFirst() + .orElse(null); // Return null if no matching enum value is found } } diff --git a/health-services/plan-service/src/main/java/digit/web/models/MetricDetail.java b/health-services/plan-service/src/main/java/digit/web/models/MetricDetail.java index 40452bb02d1..d2a4bcc2f64 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/MetricDetail.java +++ b/health-services/plan-service/src/main/java/digit/web/models/MetricDetail.java @@ -15,6 +15,7 @@ import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; +import java.util.Arrays; @Validated @Data @@ -64,12 +65,10 @@ public String toString() { @JsonCreator public static MetricComparatorEnum fromValue(String text) { - for (MetricComparatorEnum b : MetricComparatorEnum.values()) { - if (String.valueOf(b.symbol).equals(text)) { - return b; - } - } - return null; + return Arrays.stream(MetricComparatorEnum.values()) + .filter(b -> String.valueOf(b.symbol).equals(text)) + .findFirst() + .orElse(null); // Return null if no matching enum value is found } } diff --git a/health-services/plan-service/src/main/java/digit/web/models/Operation.java b/health-services/plan-service/src/main/java/digit/web/models/Operation.java index 0569dc9a536..b12c44341fb 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/Operation.java +++ b/health-services/plan-service/src/main/java/digit/web/models/Operation.java @@ -13,6 +13,8 @@ import lombok.Data; import lombok.Builder; +import java.util.Arrays; + /** * Operation */ @@ -38,14 +40,30 @@ public class Operation { @JsonProperty("assumptionValue") @NotNull - @Size(min = 2, max = 256) + @Size(min = 1, max = 256) private String assumptionValue = null; @JsonProperty("output") @NotNull - @Size(min = 1, max = 64) + @Size(min = 1, max = 256) private String output = null; + @JsonProperty("showOnEstimationDashboard") + @NotNull + private Boolean showOnEstimationDashboard = true; + + @JsonProperty("source") + @NotNull(message = "Source cannot be null. Please specify a valid source.") + private Source source = null; + + @JsonProperty("category") + @NotNull + @Size(min = 2, max = 64) + private String category = null; + + @JsonProperty("executionOrder") + private Integer executionOrder = null; + @JsonProperty("active") @NotNull private Boolean active = true; @@ -80,12 +98,10 @@ public String toString() { @JsonCreator public static OperatorEnum fromValue(String text) { - for (OperatorEnum b : OperatorEnum.values()) { - if (String.valueOf(b.value).equals(text)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + text + "'"); + return Arrays.stream(OperatorEnum.values()) + .filter(b -> String.valueOf(b.value).equals(text)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unexpected value '" + text + "'")); } } diff --git a/health-services/plan-service/src/main/java/digit/web/models/Pagination.java b/health-services/plan-service/src/main/java/digit/web/models/Pagination.java new file mode 100644 index 00000000000..6d3fd64df77 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Pagination.java @@ -0,0 +1,35 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Pagination + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Pagination { + + @JsonIgnore + private String sortBy; + + @JsonIgnore + private String sortOrder; + + @JsonProperty("limit") + @Min(1) + @Max(50) + private Integer limit; + + @JsonProperty("offset") + @Min(0) + private Integer offset; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/Plan.java b/health-services/plan-service/src/main/java/digit/web/models/Plan.java index f1fb59a400e..3ff0e8ce87d 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/Plan.java +++ b/health-services/plan-service/src/main/java/digit/web/models/Plan.java @@ -1,12 +1,15 @@ package digit.web.models; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; +import java.util.Map; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; @@ -35,14 +38,21 @@ public class Plan { @Size(min = 1, max = 64) private String locality = null; - @JsonProperty("executionPlanId") + @JsonProperty("campaignId") @Size(max = 64) - private String executionPlanId = null; + private String campaignId = null; @JsonProperty("planConfigurationId") @Size(max = 64) private String planConfigurationId = null; + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("assignee") + private List assignee = null; + @JsonProperty("additionalDetails") private Object additionalDetails = null; @@ -61,4 +71,20 @@ public class Plan { @JsonProperty("auditDetails") private AuditDetails auditDetails = null; + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonIgnore + private String boundaryAncestralPath = null; + + @JsonIgnore + private boolean isRequestFromResourceEstimationConsumer; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + } diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanConfiguration.java b/health-services/plan-service/src/main/java/digit/web/models/PlanConfiguration.java index dbf9ed7f139..50c43741d48 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/PlanConfiguration.java +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanConfiguration.java @@ -1,9 +1,6 @@ package digit.web.models; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonValue; -import jakarta.validation.constraints.NotEmpty; import java.util.ArrayList; import java.util.List; import jakarta.validation.Valid; @@ -11,6 +8,7 @@ import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Pattern; import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; @@ -38,54 +36,43 @@ public class PlanConfiguration { @JsonProperty("name") @NotNull - @Size(min = 2, max = 128) - @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must not contain only special characters") + @Size(min = 3, max = 128) private String name = null; - @JsonProperty("executionPlanId") + @JsonProperty("campaignId") @NotNull @Size(min = 2, max = 64) - @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Execution Plan Id must not contain only special characters") - private String executionPlanId = null; + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Campaign Id must not contain only special characters") + private String campaignId = null; @JsonProperty("status") - @NotNull - private StatusEnum status = null; + private String status = null; @JsonProperty("files") - @NotNull - @NotEmpty @Valid private List files = new ArrayList<>(); @JsonProperty("assumptions") - @NotNull - @NotEmpty @Valid private List assumptions = new ArrayList<>(); @JsonProperty("operations") - @NotNull - @NotEmpty @Valid private List operations = new ArrayList<>(); @JsonProperty("resourceMapping") - @NotNull - @NotEmpty @Valid private List resourceMapping = new ArrayList<>(); @JsonProperty("auditDetails") private @Valid AuditDetails auditDetails; - /** - * The status used in the Plan Configuration - */ - public enum StatusEnum { - DRAFT , - GENERATED, - INVALID_DATA - } + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + } diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java index ab7c827c49a..1f0b8f6be6f 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java @@ -1,6 +1,5 @@ package digit.web.models; -import jakarta.validation.Valid; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; @@ -12,6 +11,8 @@ import lombok.Data; import lombok.Builder; +import java.util.List; + /** * PlanConfigurationSearchCriteria */ @@ -30,14 +31,17 @@ public class PlanConfigurationSearchCriteria { @JsonProperty("id") private String id = null; + @JsonProperty("ids") + private List ids = null; + @JsonProperty("name") private String name = null; - @JsonProperty("executionPlanId") - private String executionPlanId = null; + @JsonProperty("campaignId") + private String campaignId = null; @JsonProperty("status") - private String status = null; + private List status = null; @JsonProperty("userUuid") private String userUuid = null; @@ -50,5 +54,4 @@ public class PlanConfigurationSearchCriteria { @Min(1) @Max(50) private Integer limit; - } diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanDTO.java new file mode 100644 index 00000000000..f56569c1349 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanDTO.java @@ -0,0 +1,90 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +/** + * Plan + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanDTO { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("locality") + @Size(min = 1, max = 64) + private String locality = null; + + @JsonProperty("campaignId") + @Size(max = 64) + private String campaignId = null; + + @JsonProperty("planConfigurationId") + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonProperty("activities") + @Valid + private List activities; + + @JsonProperty("resources") + @Valid + private List resources; + + @JsonProperty("targets") + @Valid + private List targets; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("boundaryAncestralPath") + private String boundaryAncestralPath = null; + + @JsonIgnore + private Boolean partnerAssignmentValidationEnabled; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignment.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignment.java new file mode 100644 index 00000000000..c27b1e1eb1b --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignment.java @@ -0,0 +1,71 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Set; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PlanEmployeeAssignment + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignment { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(min = 2, max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("employeeId") + @NotNull + @Size(min = 2, max = 64) + private String employeeId = null; + + @JsonProperty("role") + @NotNull + @Size(min = 2, max = 64) + private String role = null; + + @JsonProperty("hierarchyLevel") + @Size(min = 2, max = 64) + private String hierarchyLevel = null; + + @JsonProperty("jurisdiction") + @Valid + @NotEmpty + private Set jurisdiction = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentDTO.java new file mode 100644 index 00000000000..555d916c1ff --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentDTO.java @@ -0,0 +1,69 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PlanEmployeeAssignmentDTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentDTO { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(min = 2, max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("employeeId") + @NotNull + @Size(min = 2, max = 64) + private String employeeId = null; + + @JsonProperty("role") + @NotNull + @Size(min = 2, max = 64) + private String role = null; + + @JsonProperty("hierarchyLevel") + @Size(min = 2, max = 64) + private String hierarchyLevel = null; + + @JsonProperty("jurisdiction") + @Valid + @NotEmpty + private String jurisdiction = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequest.java new file mode 100644 index 00000000000..4361b16dde2 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequest.java @@ -0,0 +1,30 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + + +/** + * PlanEmployeeAssignmentRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanEmployeeAssignment") + @Valid + private PlanEmployeeAssignment planEmployeeAssignment = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequestDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequestDTO.java new file mode 100644 index 00000000000..f21bc83a3e8 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequestDTO.java @@ -0,0 +1,30 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + + +/** + * PlanEmployeeAssignmentRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentRequestDTO { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanEmployeeAssignment") + @Valid + private PlanEmployeeAssignmentDTO planEmployeeAssignmentDTO = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentResponse.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentResponse.java new file mode 100644 index 00000000000..6c6ecdc516c --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentResponse.java @@ -0,0 +1,36 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import jakarta.validation.Valid; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + + +/** + * PlanEmployeeAssignmentResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("PlanEmployeeAssignment") + @Valid + private List planEmployeeAssignment = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; +} + diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchCriteria.java new file mode 100644 index 00000000000..22008b64135 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchCriteria.java @@ -0,0 +1,72 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Set; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PlanEmployeeAssignmentSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentSearchCriteria { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @Size(min = 2, max = 100) + @NotNull + private String tenantId = null; + + @JsonProperty("employeeId") + private List employeeId = null; + + @JsonProperty("planConfigurationId") + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("planConfigurationStatus") + private Set planConfigurationStatus = null; + + @JsonProperty("role") + @Valid + private List role = null; + + @JsonProperty("hierarchyLevel") + private String hierarchyLevel = null; + + @JsonProperty("jurisdiction") + @Valid + private List jurisdiction = null; + + @JsonProperty("active") + @Builder.Default + private Boolean active = Boolean.TRUE; + + @JsonProperty("filterUniqueByPlanConfig") + @Builder.Default + private Boolean filterUniqueByPlanConfig = Boolean.FALSE; + + @JsonProperty("offset") + private Integer offset = null; + + @JsonProperty("limit") + private Integer limit = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchRequest.java new file mode 100644 index 00000000000..a8b3a40a41f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchRequest.java @@ -0,0 +1,29 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PlanEmployeeAssignmentSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentSearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanEmployeeAssignmentSearchCriteria") + @Valid + private PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacility.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacility.java new file mode 100644 index 00000000000..87c024324ac --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacility.java @@ -0,0 +1,92 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Plan Facility + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacility { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("boundaryAncestralPath") + private String boundaryAncestralPath = null; + + @JsonProperty("facilityId") + @NotNull + @Size(max = 64) + private String facilityId = null; + + @JsonProperty("facilityName") + private String facilityName = null; + + @JsonProperty("residingBoundary") + @NotNull + @Size(min = 1, max = 64) + private String residingBoundary = null; + + @JsonProperty("serviceBoundaries") + @NotNull + @Valid + private List serviceBoundaries; + + @JsonIgnore + private List initiallySetServiceBoundaries; + + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + @NotNull + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + public PlanFacility addServiceBoundariesItem(String serviceBoundariesItem) { + if (this.serviceBoundaries == null) { + this.serviceBoundaries = new ArrayList<>(); + } + this.serviceBoundaries.add(serviceBoundariesItem); + return this; + } + + + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityDTO.java new file mode 100644 index 00000000000..771c602f760 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityDTO.java @@ -0,0 +1,79 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +/** + * Plan Facility DTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityDTO { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("boundaryAncestralPath") + private String boundaryAncestralPath = null; + + @JsonProperty("facilityId") + @NotNull + @Size(max = 64) + private String facilityId = null; + + @JsonProperty("residingBoundary") + @NotNull + @Size(min = 1, max = 64) + private String residingBoundary = null; + + // Changed List to String to store as JSON + @JsonProperty("serviceBoundaries") + @NotNull + @Size(min = 1) + private String serviceBoundaries = null; // Store as JSON string + + @JsonProperty("initiallySetServiceBoundaries") + private List initiallySetServiceBoundaries; + + @JsonProperty("facilityName") + private String facilityName = null; + + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + @NotNull + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequest.java new file mode 100644 index 00000000000..9eb2652d0a7 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequest.java @@ -0,0 +1,33 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanFacilityRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityRequest { + + @JsonProperty("RequestInfo") + @Valid + @NotNull + private RequestInfo requestInfo; + + @JsonProperty("PlanFacility") + @Valid + @NotNull + private PlanFacility planFacility; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequestDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequestDTO.java new file mode 100644 index 00000000000..a78b2ba0047 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequestDTO.java @@ -0,0 +1,33 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanFacilityRequestDTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityRequestDTO { + + @JsonProperty("RequestInfo") + @Valid + @NotNull + private RequestInfo requestInfo; + + @JsonProperty("PlanFacility") + @Valid + @NotNull + private PlanFacilityDTO planFacilityDTO; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityResponse.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityResponse.java new file mode 100644 index 00000000000..1ac3db052c6 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityResponse.java @@ -0,0 +1,33 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; +import java.util.List; + +/** + * PlanFacilityResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityResponse { + + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo = null; + + @JsonProperty("PlanFacility") + @Valid + private List planFacility = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchCriteria.java new file mode 100644 index 00000000000..a5a4e49c42c --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchCriteria.java @@ -0,0 +1,64 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilitySearchCriteria { + + @JsonProperty("ids") + private Set ids = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("facilityName") + private String facilityName = null; + + @JsonProperty("facilityStatus") + private String facilityStatus = null; + + @JsonProperty("facilityType") + private String facilityType = null; + + @JsonProperty("residingBoundaries") + private List residingBoundaries = null; + + @JsonProperty("jurisdiction") + private List jurisdiction = null; + + @JsonProperty("facilityId") + private String facilityId = null; + + @JsonProperty("offset") + private Integer offset = null; + + @JsonProperty("limit") + private Integer limit = null; + + @JsonIgnore + private Map filtersMap = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchRequest.java new file mode 100644 index 00000000000..65517af3d18 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchRequest.java @@ -0,0 +1,34 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; + +/** + * PlanFacilitySearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilitySearchRequest { + + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanFacilitySearchCriteria") + @NotNull + @Valid + private PlanFacilitySearchCriteria planFacilitySearchCriteria = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanRequestDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanRequestDTO.java new file mode 100644 index 00000000000..1b60fca0696 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanRequestDTO.java @@ -0,0 +1,29 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanCreateRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanRequestDTO { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Plan") + @Valid + private PlanDTO planDTO = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java b/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java index bf08ba0059c..51e11ec94a5 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; +import java.util.Map; + import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; import jakarta.validation.Valid; @@ -28,4 +30,12 @@ public class PlanResponse { @Valid private List plan = null; + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + @JsonProperty("StatusCount") + @Valid + private Map statusCount = null; + } diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/PlanSearchCriteria.java index 6e9cc9449d1..357b306fa8f 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/PlanSearchCriteria.java +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanSearchCriteria.java @@ -1,15 +1,16 @@ package digit.web.models; -import java.util.Set; - import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; -import lombok.Data; import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Set; /** * PlanSearchCriteria @@ -29,14 +30,24 @@ public class PlanSearchCriteria { private String tenantId = null; @JsonProperty("locality") - private String locality = null; + private List locality = null; - @JsonProperty("executionPlanId") - private String executionPlanId = null; + @JsonProperty("campaignId") + private String campaignId = null; @JsonProperty("planConfigurationId") private String planConfigurationId = null; + @JsonProperty("status") + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("jurisdiction") + @Valid + private List jurisdiction = null; + @JsonProperty("offset") private Integer offset = null; diff --git a/health-services/plan-service/src/main/java/digit/web/models/RequestInfoWrapper.java b/health-services/plan-service/src/main/java/digit/web/models/RequestInfoWrapper.java new file mode 100644 index 00000000000..9613a753b82 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/RequestInfoWrapper.java @@ -0,0 +1,18 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Component +public class RequestInfoWrapper { + + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/Resource.java b/health-services/plan-service/src/main/java/digit/web/models/Resource.java index 0b64b3108c1..d0d8ce2500b 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/Resource.java +++ b/health-services/plan-service/src/main/java/digit/web/models/Resource.java @@ -25,7 +25,7 @@ public class Resource { @JsonProperty("resourceType") @NotNull - @Size(min = 2, max = 256) + @Size(min = 1, max = 256) private String resourceType = null; @JsonProperty("estimatedNumber") diff --git a/health-services/plan-service/src/main/java/digit/web/models/Source.java b/health-services/plan-service/src/main/java/digit/web/models/Source.java new file mode 100644 index 00000000000..e58bfba27be --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Source.java @@ -0,0 +1,5 @@ +package digit.web.models; + +public enum Source { + MDMS, CUSTOM, VEHICLE; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java new file mode 100644 index 00000000000..7f92e1f53c8 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java @@ -0,0 +1,42 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * BoundarySearchResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("TenantBoundary") + @Valid + private List tenantBoundary = null; + + + public BoundarySearchResponse addTenantBoundaryItem(HierarchyRelation tenantBoundaryItem) { + if (this.tenantBoundary == null) { + this.tenantBoundary = new ArrayList<>(); + } + this.tenantBoundary.add(tenantBoundaryItem); + return this; + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java new file mode 100644 index 00000000000..45ab5a19141 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java @@ -0,0 +1,30 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryTypeHierarchy + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchy { + + @JsonProperty("boundaryType") + private String boundaryType = null; + + @JsonProperty("parentBoundaryType") + private String parentBoundaryType = null; + + @JsonProperty("active") + private Boolean active = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java new file mode 100644 index 00000000000..6faf8ac0b49 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java @@ -0,0 +1,45 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * BoundaryTypeHierarchyDefinition + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchyDefinition { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("hierarchyType") + private String hierarchyType = null; + + @JsonProperty("boundaryHierarchy") + @Valid + private List boundaryHierarchy = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("boundaryHierarchyJsonNode") + private JsonNode boundaryHierarchyJsonNode = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java new file mode 100644 index 00000000000..6372620c43c --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java @@ -0,0 +1,36 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * BoundaryTypeHierarchyResponse + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchyResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("totalCount") + private Integer totalCount = null; + + @JsonProperty("BoundaryHierarchy") + @Valid + private List boundaryHierarchy = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java new file mode 100644 index 00000000000..ba335f7f037 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java @@ -0,0 +1,39 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryTypeHierarchySearchCriteria + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchySearchCriteria { + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @Size(min = 1, max = 100) + private String hierarchyType = null; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} + diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java new file mode 100644 index 00000000000..46cb6eb463a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java @@ -0,0 +1,31 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryTypeHierarchySearchRequest + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchySearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("BoundaryTypeHierarchySearchCriteria") + @Valid + private BoundaryTypeHierarchySearchCriteria boundaryTypeHierarchySearchCriteria = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java new file mode 100644 index 00000000000..c42af3737ce --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java @@ -0,0 +1,42 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * EnrichedBoundary + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class EnrichedBoundary { + + @JsonProperty("id") + private String id; + + @JsonProperty("code") + @NotNull + private String code; + + @JsonProperty("boundaryType") + private String boundaryType; + + @JsonProperty("children") + @Valid + private List children = null; + + @JsonIgnore + private String parent = null; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java new file mode 100644 index 00000000000..7a3e26f6595 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java @@ -0,0 +1,34 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.List; + +/** + * HierarchyRelation + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class HierarchyRelation { + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("hierarchyType") + private String hierarchyType = null; + + @JsonProperty("boundary") + @Valid + private List boundary = null; + + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/AdditionalField.java b/health-services/plan-service/src/main/java/digit/web/models/census/AdditionalField.java new file mode 100644 index 00000000000..65ae4222831 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/AdditionalField.java @@ -0,0 +1,48 @@ +package digit.web.models.census; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * AdditionalField + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AdditionalField { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("key") + @Valid + @NotNull + private String key = null; + + @JsonProperty("value") + @Valid + @NotNull + private BigDecimal value = null; + + @JsonProperty("showOnUi") + private Boolean showOnUi = Boolean.TRUE; + + @JsonProperty("editable") + private Boolean editable = Boolean.TRUE; + + @JsonProperty("order") + private Integer order = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/Census.java b/health-services/plan-service/src/main/java/digit/web/models/census/Census.java new file mode 100644 index 00000000000..e8f384d1e98 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/Census.java @@ -0,0 +1,139 @@ +package digit.web.models.census; + + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +import java.util.List; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; + + +/** + * Census + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Census { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @NotNull + private String hierarchyType = null; + + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode = null; + + @JsonProperty("assignee") + @Size(max = 64) + private String assignee = null; + + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("type") + @NotNull + private TypeEnum type = null; + + @JsonProperty("totalPopulation") + @NotNull + private Long totalPopulation = null; + + @JsonProperty("populationByDemographics") + @Valid + private List populationByDemographics = null; + + @JsonProperty("additionalFields") + @Valid + private List additionalFields = null; + + @JsonProperty("effectiveFrom") + private Long effectiveFrom = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("source") + @NotNull + private String source = null; + + @JsonIgnore + private List boundaryAncestralPath = null; + + @JsonIgnore + @Builder.Default + private Boolean partnerAssignmentValidationEnabled = Boolean.TRUE; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; + + /** + * Gets or Sets type + */ + public enum TypeEnum { + PEOPLE("people"), + ANIMALS("animals"), + PLANTS("plants"), + OTHER("other"); + + private String value; + + TypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static TypeEnum fromValue(String text) { + for (TypeEnum b : TypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/CensusResponse.java b/health-services/plan-service/src/main/java/digit/web/models/census/CensusResponse.java new file mode 100644 index 00000000000..dabc56422b6 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/CensusResponse.java @@ -0,0 +1,42 @@ +package digit.web.models.census; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Map; + +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Census") + @Valid + private List census = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + @JsonProperty("StatusCount") + @Valid + private Map statusCount = null; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchCriteria.java new file mode 100644 index 00000000000..4a5a1414d19 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchCriteria.java @@ -0,0 +1,72 @@ +package digit.web.models.census; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.springframework.validation.annotation.Validated; +import jakarta.validation.constraints.*; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchCriteria { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("ids") + private Set ids = null; + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + private String tenantId = null; + + @JsonProperty("areaCodes") + private List areaCodes = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("source") + private String source = null; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("jurisdiction") + private List jurisdiction = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("limit") + private Integer limit = null; + + @JsonProperty("offset") + private Integer offset = null; + + public CensusSearchCriteria addAreaCodesItem(String areaCodesItem) { + if (this.areaCodes == null) { + this.areaCodes = new ArrayList<>(); + } + this.areaCodes.add(areaCodesItem); + return this; + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchRequest.java new file mode 100644 index 00000000000..157cf16870f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchRequest.java @@ -0,0 +1,31 @@ +package digit.web.models.census; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("CensusSearchCriteria") + @Valid + private CensusSearchCriteria censusSearchCriteria = null; + + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/PopulationByDemographic.java b/health-services/plan-service/src/main/java/digit/web/models/census/PopulationByDemographic.java new file mode 100644 index 00000000000..b36d25b21de --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/PopulationByDemographic.java @@ -0,0 +1,69 @@ +package digit.web.models.census; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PopulationByDemographic + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PopulationByDemographic { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("demographicVariable") + private DemographicVariableEnum demographicVariable = null; + + @JsonProperty("populationDistribution") + private Object populationDistribution = null; + + /** + * Gets or Sets demographicVariable + */ + public enum DemographicVariableEnum { + AGE("age"), + + GENDER("gender"), + + ETHNICITY("ethnicity"); + + private String value; + + DemographicVariableEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DemographicVariableEnum fromValue(String text) { + for (DemographicVariableEnum b : DemographicVariableEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/AdditionalFields.java b/health-services/plan-service/src/main/java/digit/web/models/facility/AdditionalFields.java new file mode 100644 index 00000000000..e3b7f19cd31 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/AdditionalFields.java @@ -0,0 +1,25 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AdditionalFields { + + @JsonProperty("schema") + private String schema; + + @JsonProperty("version") + private int version; + + @JsonProperty("fields") + private List fields; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/Address.java b/health-services/plan-service/src/main/java/digit/web/models/facility/Address.java new file mode 100644 index 00000000000..f6a5e2c8c0b --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/Address.java @@ -0,0 +1,62 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Address { + + @JsonProperty("id") + private String id; + + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("clientReferenceId") + private String clientReferenceId; + + @JsonProperty("doorNo") + private String doorNo; + + @JsonProperty("latitude") + private Double latitude; + + @JsonProperty("longitude") + private Double longitude; + + @JsonProperty("locationAccuracy") + private Double locationAccuracy; + + @JsonProperty("type") + private String type; + + @JsonProperty("addressLine1") + private String addressLine1; + + @JsonProperty("addressLine2") + private String addressLine2; + + @JsonProperty("landmark") + private String landmark; + + @JsonProperty("city") + private String city; + + @JsonProperty("pincode") + private String pincode; + + @JsonProperty("buildingName") + private String buildingName; + + @JsonProperty("street") + private String street; + + @JsonProperty("locality") + private Locality locality; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/Facility.java b/health-services/plan-service/src/main/java/digit/web/models/facility/Facility.java new file mode 100644 index 00000000000..fcfec9b1ee9 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/Facility.java @@ -0,0 +1,64 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; + +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Facility { + @JsonProperty("id") + private String id; + + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("source") + private String source; + + @JsonProperty("rowVersion") + private Integer rowVersion; + + @JsonProperty("applicationId") + private String applicationId; + + @JsonProperty("hasErrors") + private boolean hasErrors; + + @JsonProperty("additionalFields") + private AdditionalFields additionalFields; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails; + + @JsonProperty("clientReferenceId") + private String clientReferenceId; + + @JsonProperty("clientAuditDetails") + private String clientAuditDetails; + + @JsonProperty("isPermanent") + private boolean isPermanent; + + @JsonProperty("name") + private String name; + + @JsonProperty("usage") + private String usage; + + @JsonProperty("storageCapacity") + private Integer storageCapacity; + + @JsonProperty("address") + private Address address; + + @JsonProperty("isDeleted") + private boolean isDeleted; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityDetail.java b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityDetail.java new file mode 100644 index 00000000000..9f09df28102 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityDetail.java @@ -0,0 +1,19 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FacilityDetail { + @JsonProperty("facility") + private Facility facility; + + @JsonProperty("additionalInfo") + private String additionalInfo; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityResponse.java b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityResponse.java new file mode 100644 index 00000000000..46e98759e48 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityResponse.java @@ -0,0 +1,22 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FacilityResponse { + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo; + + @JsonProperty("Facilities") + private List facilities; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchCriteria.java new file mode 100644 index 00000000000..ae76b88fa4a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchCriteria.java @@ -0,0 +1,30 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.web.models.Pagination; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FacilitySearchCriteria { + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("id") + private List id; + + @JsonProperty("name") + private String name; + + @JsonProperty("isDeleted") + private Boolean isDeleted; + + @JsonProperty("pagination") + private Pagination pagination; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchRequest.java new file mode 100644 index 00000000000..c7d39e4053e --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchRequest.java @@ -0,0 +1,20 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FacilitySearchRequest { + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + @JsonProperty("Facility") + private FacilitySearchCriteria facilitySearchCriteria; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/Field.java b/health-services/plan-service/src/main/java/digit/web/models/facility/Field.java new file mode 100644 index 00000000000..3cbd343bf76 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/Field.java @@ -0,0 +1,20 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Field { + + @JsonProperty("key") + private String key; + + @JsonProperty("value") + private String value; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/Locality.java b/health-services/plan-service/src/main/java/digit/web/models/facility/Locality.java new file mode 100644 index 00000000000..68552c0898a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/Locality.java @@ -0,0 +1,33 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Locality { + + @JsonProperty("id") + private String id; + + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("code") + private String code; + + @JsonProperty("geometry") + private String geometry; // Assuming geometry is a string, adjust based on your actual data + + @JsonProperty("auditDetails") + private AuditDetails auditDetails; + + @JsonProperty("additionalDetails") + private String additionalDetails; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/Mdms.java b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/Mdms.java new file mode 100644 index 00000000000..be5e324cd5f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/Mdms.java @@ -0,0 +1,55 @@ +package digit.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * Mdms + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Mdms { + + @JsonProperty("id") + @Size(min = 2, max = 64) + private String id; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 128) + private String tenantId = null; + + @JsonProperty("schemaCode") + @NotNull + @Size(min = 2, max = 128) + private String schemaCode = null; + + @JsonProperty("uniqueIdentifier") + @Size(min = 2, max = 128) + private String uniqueIdentifier = null; + + @JsonProperty("data") + @NotNull + private JsonNode data = null; + + @JsonProperty("isActive") + private Boolean isActive = true; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaReqV2.java b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaReqV2.java new file mode 100644 index 00000000000..f6af90e1b82 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaReqV2.java @@ -0,0 +1,23 @@ +package digit.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class MdmsCriteriaReqV2 { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo; + + @JsonProperty("MdmsCriteria") + @Valid + private MdmsCriteriaV2 mdmsCriteriaV2; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaV2.java b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaV2.java new file mode 100644 index 00000000000..88e8a715810 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaV2.java @@ -0,0 +1,62 @@ +package digit.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Data +@Validated +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class MdmsCriteriaV2 { + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + @NotNull + private String tenantId; + + @JsonProperty("ids") + private Set ids; + + @JsonProperty("uniqueIdentifier") + @Size(min = 1, max = 64) + private String uniqueIdentifier; + + @JsonProperty("uniqueIdentifiers") + private List uniqueIdentifiers; + + @JsonProperty("schemaCode") + private String schemaCode; + + @JsonProperty("filters") + private Map filterMap; + + @JsonProperty("isActive") + private Boolean isActive; + + @JsonIgnore + private Map schemaCodeFilterMap; + + @JsonIgnore + private Set uniqueIdentifiersForRefVerification; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsResponseV2.java b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsResponseV2.java new file mode 100644 index 00000000000..090b41f90da --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsResponseV2.java @@ -0,0 +1,25 @@ +package digit.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.egov.common.contract.response.ResponseInfo; + +import javax.validation.Valid; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) + +public class MdmsResponseV2 { + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("mdms") + @Valid + private List mdms = null; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Boundary.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Boundary.java new file mode 100644 index 00000000000..a1b725cbd6f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Boundary.java @@ -0,0 +1,32 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Boundary + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Boundary { + + @JsonProperty("code") + private String code; + + @JsonProperty("type") + private String type; + + @JsonProperty("isRoot") + private Boolean isRoot; + + @JsonProperty("includeAllChildren") + private Boolean includeAllChildren; + + @JsonProperty("parent") + private String parent; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignDetail.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignDetail.java new file mode 100644 index 00000000000..ee9d064547a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignDetail.java @@ -0,0 +1,85 @@ +package digit.web.models.projectFactory; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; + +import java.util.List; + +/** + * CampaignDetails + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignDetail { + + @JsonProperty("id") + private String id; + + @JsonProperty("tenantId") + @NotNull + private String tenantId; + + @JsonProperty("status") + private String status; + + @JsonProperty("action") + private String action; + + @JsonProperty("campaignNumber") + private String campaignNumber; + + @JsonProperty("isActive") + private Boolean isActive; + + @JsonProperty("parentId") + private String parentId; + + @JsonProperty("campaignName") + private String campaignName; + + @JsonProperty("projectType") + private String projectType; + + @JsonProperty("hierarchyType") + private String hierarchyType; + + @JsonProperty("boundaryCode") + private String boundaryCode; + + @JsonProperty("projectId") + private String projectId; + + @JsonProperty("startDate") + private Long startDate; + + @JsonProperty("endDate") + private Long endDate; + + @JsonProperty("additionalDetails") + @Valid + private Object additionalDetails; + + @JsonProperty("resources") + @Valid + private List resources; + + @JsonProperty("boundaries") + @Valid + private List boundaries; + + @JsonProperty("deliveryRules") + @Valid + private List deliveryRules; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignResponse.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignResponse.java new file mode 100644 index 00000000000..e03e4bb01c7 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignResponse.java @@ -0,0 +1,29 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.*; +import org.egov.common.contract.response.ResponseInfo; + +import java.util.List; + +/** + * CampaignResponse + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CampaignResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("CampaignDetails") + @Valid + private List campaignDetails = null; + + @JsonProperty("totalCount") + @Valid + private Integer totalCount = null; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchCriteria.java new file mode 100644 index 00000000000..36ef6675594 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchCriteria.java @@ -0,0 +1,51 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * CampaignSearchCriteria + */ +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@Validated +public class CampaignSearchCriteria { + + @JsonProperty("ids") + @Size(min = 1) + private List ids; + + @JsonProperty("tenantId") + @Size(min = 2, max = 256) + private String tenantId; + + @JsonIgnore + private List status; + + @JsonIgnore + private String createdBy; + + @JsonIgnore + private Boolean campaignsIncludeDates; + + @JsonIgnore + private Integer startDate; + + @JsonIgnore + private Integer endDate; + + @JsonProperty("pagination") + @Valid + private Pagination pagination; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchReq.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchReq.java new file mode 100644 index 00000000000..391420396ed --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchReq.java @@ -0,0 +1,22 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.Builder; +import lombok.Data; +import org.egov.common.contract.request.RequestInfo; + +/** + * CampaignSearchReq + */ +@Data +@Builder +public class CampaignSearchReq { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo; + + @JsonProperty("CampaignDetails") + private CampaignSearchCriteria campaignSearchCriteria; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Condition.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Condition.java new file mode 100644 index 00000000000..5ad19e29aef --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Condition.java @@ -0,0 +1,27 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Condition + **/ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Condition { + + @JsonProperty("value") + private String value; + + @JsonProperty("operator") + private String operator; + + @JsonProperty("attribute") + private String attribute; +} + diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/DeliveryRule.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/DeliveryRule.java new file mode 100644 index 00000000000..7eef58fd8ae --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/DeliveryRule.java @@ -0,0 +1,43 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * DeliveryRule + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DeliveryRule { + + @JsonProperty("endDate") + private Long endDate; + + @JsonProperty("products") + @Valid + private List products; + + @JsonProperty("startDate") + private Long startDate; + + @JsonProperty("conditions") + @Valid + private List conditions; + + @JsonProperty("cycleNumber") + private Integer cycleNumber; + + @JsonProperty("deliveryNumber") + private Integer deliveryNumber; + + @JsonProperty("deliveryRuleNumber") + private Integer deliveryRuleNumber; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Pagination.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Pagination.java new file mode 100644 index 00000000000..7e8d28c30ce --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Pagination.java @@ -0,0 +1,35 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Pagination + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Pagination { + + @JsonIgnore + private String sortBy; + + @JsonIgnore + private String sortOrder; + + @JsonProperty("limit") + @Min(1) + @Max(50) + private Integer limit; + + @JsonProperty("offset") + @Min(0) + private Integer offset; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Product.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Product.java new file mode 100644 index 00000000000..9c4e560cc7f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Product.java @@ -0,0 +1,26 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Product + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Product { + + @JsonProperty("name") + private String name; + + @JsonProperty("count") + private Integer count; + + @JsonProperty("value") + private String value; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Resource.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Resource.java new file mode 100644 index 00000000000..07f04a281bb --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Resource.java @@ -0,0 +1,32 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Resource + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Resource { + + @JsonProperty("type") + private String type; + + @JsonProperty("filename") + private String filename; + + @JsonProperty("resourceId") + private String resourceId; + + @JsonProperty("filestoreId") + private String filestoreId; + + @JsonProperty("createResourceId") + private String createResourceId; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/resources/application.properties b/health-services/plan-service/src/main/resources/application.properties index 03ee3da916d..cb941721390 100644 --- a/health-services/plan-service/src/main/resources/application.properties +++ b/health-services/plan-service/src/main/resources/application.properties @@ -30,6 +30,7 @@ spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.Strin spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer spring.kafka.listener.missing-topics-fatal=false spring.kafka.consumer.properties.spring.json.use.type.headers=false +spring.kafka.producer.properties.max.request.size=3000000 # KAFKA CONSUMER CONFIGURATIONS kafka.consumer.config.auto_commit=true @@ -48,14 +49,57 @@ plan.configuration.update.topic=plan-config-update-topic plan.create.topic=save-plan plan.update.topic=update-plan +plan.bulk.update.topic=bulk-update-plan -#mdms urls +plan.facility.update.topic=update-plan-facility +plan.facility.create.topic=save-plan-facility + +plan.employee.assignment.create.topic=plan-employee-assignment-create-topic +plan.employee.assignment.update.topic=plan-employee-assignment-update-topic + +# Census +egov.census.host=https://unified-dev.digit.org +egov.census.search.endpoint=/census-service/_search + +# Facility +egov.facility.host=https://unified-dev.digit.org +egov.facility.search.endpoint=/facility/v1/_search + +# MDMS urls egov.mdms.host=https://unified-dev.digit.org -egov.mdms.search.endpoint=/egov-mdms-service/v1/_search +egov.mdms.search.endpoint=/mdms-v2/v1/_search +egov.mdms.search.v2.endpoint=/mdms-v2/v2/_search + +# Project factory urls +egov.project.factory.host=https://unified-dev.digit.org +egov.project.factory.search.endpoint=/project-factory/v1/project-type/search + +#User Service +egov.user.service.host=https://unified-dev.digit.org +egov.user.search.endpoint=/user/_search + +#Boundary service urls +egov.boundary.service.host=https://unified-dev.digit.org +egov.boundary.relationship.search.endpoint=/boundary-service/boundary-relationships/_search +egov.boundary.hierarchy.search.endpoint=/boundary-service/boundary-hierarchy-definition/_search + +# Workflow +egov.workflow.host=https://unified-dev.digit.org +egov.workflow.transition.path=/egov-workflow-v2/egov-wf/process/_transition +egov.business.service.search.endpoint=/egov-workflow-v2/egov-wf/businessservice/_search +workflow.initiate.action=INITIATE +workflow.intermediate.action=EDIT_AND_SEND_FOR_APPROVAL,APPROVE +workflow.send.back.actions=SEND_BACK_FOR_CORRECTION # Pagination config plan.default.offset=0 plan.default.limit=10 +# CONSUMER TOPICS resource.config.consumer.plan.create.topic=resource-microplan-create-topic -resource.update.plan.config.consumer.topic=resource-plan-config-update-topic \ No newline at end of file +resource.update.plan.config.consumer.topic=resource-plan-config-update-topic +project.factory.save.plan.facility.consumer.topic=project-factory-save-plan-facility + +# Role Map +plan.estimation.approver.roles = ROOT_PLAN_ESTIMATION_APPROVER, PLAN_ESTIMATION_APPROVER +role.map = {'ROOT_FACILITY_CATCHMENT_MAPPER':'FACILITY_CATCHMENT_MAPPER', 'FACILITY_CATCHMENT_MAPPER':'ROOT_FACILITY_CATCHMENT_MAPPER', 'ROOT_POPULATION_DATA_APPROVER':'POPULATION_DATA_APPROVER', 'POPULATION_DATA_APPROVER':'ROOT_POPULATION_DATA_APPROVER', 'ROOT_PLAN_ESTIMATION_APPROVER':'PLAN_ESTIMATION_APPROVER', 'PLAN_ESTIMATION_APPROVER':'ROOT_PLAN_ESTIMATION_APPROVER'} diff --git a/health-services/plan-service/src/main/resources/db/Dockerfile b/health-services/plan-service/src/main/resources/db/Dockerfile index 60fc07ce69f..f38638a269f 100644 --- a/health-services/plan-service/src/main/resources/db/Dockerfile +++ b/health-services/plan-service/src/main/resources/db/Dockerfile @@ -1,4 +1,4 @@ -FROM egovio/flyway:4.1.2 +FROM egovio/flyway:10.7.1 COPY ./migration/main /flyway/sql @@ -6,4 +6,4 @@ COPY migrate.sh /usr/bin/migrate.sh RUN chmod +x /usr/bin/migrate.sh -CMD ["/usr/bin/migrate.sh"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/migrate.sh"] diff --git a/health-services/plan-service/src/main/resources/db/migrate.sh b/health-services/plan-service/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/health-services/plan-service/src/main/resources/db/migrate.sh +++ b/health-services/plan-service/src/main/resources/db/migrate.sh @@ -1,3 +1,3 @@ #!/bin/sh -flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true -ignoreMissingMigrations=true migrate \ No newline at end of file +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true migrate diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20240305113045__plan_configuration_create_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20240305113045__plan_configuration_create_ddl.sql index e9630421bcb..fa1cc87dc6a 100644 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20240305113045__plan_configuration_create_ddl.sql +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20240305113045__plan_configuration_create_ddl.sql @@ -1,9 +1,11 @@ -- Table: plan_configuration CREATE TABLE plan_configuration ( id character varying(64), - tenant_id character varying(64), - name character varying(128), - execution_plan_id character varying(64), + tenant_id character varying(64) not null, + name character varying(128) not null, + campaign_id character varying(64) not null, + status character varying(64) not null, + additional_details JSONB, created_by character varying(64), created_time bigint, last_modified_by character varying(64), @@ -16,8 +18,10 @@ CREATE TABLE plan_configuration ( CREATE TABLE plan_configuration_files ( id character varying(64), plan_configuration_id character varying(64), - filestore_id character varying(128), - input_file_type character varying(64), + filestore_id character varying(128) not null, + input_file_type character varying(64) not null, + template_identifier character varying(128) not null, + active boolean not null, created_by character varying(64), created_time bigint, last_modified_by character varying(64), @@ -30,9 +34,12 @@ CREATE TABLE plan_configuration_files ( -- Table: plan_configuration_assumptions CREATE TABLE plan_configuration_assumptions ( id character varying(64), - key character varying(256), - value numeric(12,2), + key character varying(256) not null, + value numeric(12,2) not null, + source character varying(64), + category character varying(64), plan_configuration_id character varying(64), + active boolean not null, created_by character varying(64), created_time bigint, last_modified_by character varying(64), @@ -45,10 +52,15 @@ CREATE TABLE plan_configuration_assumptions ( -- Table: plan_configuration_operations CREATE TABLE plan_configuration_operations ( id character varying(64), - input character varying(256), - operator character varying(64), - assumption_value character varying(256), - output character varying(64), + input character varying(256) not null, + operator character varying(64) not null, + assumption_value character varying(256) not null, + output character varying(256) not null, + show_on_estimation_dashboard boolean, + source character varying(64), + category character varying(64), + active boolean not null, + execution_order numeric(12,2), plan_configuration_id character varying(64), created_by character varying(64), created_time bigint, @@ -62,8 +74,10 @@ CREATE TABLE plan_configuration_operations ( -- Table: plan_configuration_mapping CREATE TABLE plan_configuration_mapping ( id character varying(64), - mapped_from character varying(256), - mapped_to character varying(256), + mapped_from character varying(256) not null, + mapped_to character varying(256) not null, + filestore_id character varying(128) not null, + active boolean not null, plan_configuration_id character varying(64), created_by character varying(64), created_time bigint, diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20240305113047__plan_create_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20240305113047__plan_create_ddl.sql index 942cc36af38..b8a194f4afa 100644 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20240305113047__plan_create_ddl.sql +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20240305113047__plan_create_ddl.sql @@ -2,7 +2,10 @@ CREATE TABLE plan ( id varchar(64), tenant_id varchar(64), locality varchar(64), - execution_plan_id varchar(64), + campaign_id varchar(64), + status character varying(64) not null, + assignee varchar(64), + boundary_ancestral_path TEXT, plan_configuration_id varchar(64), additional_details JSONB, created_by varchar(64), diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20240404113045__plan_configuration_add_filestoreid_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20240404113045__plan_configuration_add_filestoreid_ddl.sql deleted file mode 100644 index fcd7cfe2bbc..00000000000 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20240404113045__plan_configuration_add_filestoreid_ddl.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE plan_configuration_mapping ADD filestore_id character varying(128); diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20240404150000__plan_configuration_add_template_identifier_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20240404150000__plan_configuration_add_template_identifier_ddl.sql deleted file mode 100644 index e1c67ff2696..00000000000 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20240404150000__plan_configuration_add_template_identifier_ddl.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE plan_configuration_files ADD template_identifier character varying(128); diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20240923113045__plan_facility_create_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20240923113045__plan_facility_create_ddl.sql new file mode 100644 index 00000000000..0f037765d8f --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20240923113045__plan_facility_create_ddl.sql @@ -0,0 +1,19 @@ +-- Table: plan_facility_linkage +CREATE TABLE plan_facility_linkage ( + id varchar(64), + tenant_id varchar(64), + plan_configuration_id varchar(64), + facility_id varchar(64), + residing_boundary varchar(64), + service_boundaries TEXT, + additional_details JSONB, + plan_configuration_name character varying(128), + facility_name character varying(64), + active boolean, + created_by varchar(64), + created_time bigint, + last_modified_by varchar(64), + last_modified_time bigint, + CONSTRAINT uk_plan_facility_linkage_id PRIMARY KEY (id), + FOREIGN KEY (plan_configuration_id) REFERENCES plan_configuration(id) +); \ No newline at end of file diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20241604150000__plan_configuration_add_status_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20241604150000__plan_configuration_add_status_ddl.sql deleted file mode 100644 index 8683e34faef..00000000000 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20241604150000__plan_configuration_add_status_ddl.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE plan_configuration ADD status character varying(64); -UPDATE plan_configuration SET status = 'DRAFT' WHERE status IS NULL; diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20242105150000__plan_configuration_add_active_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20242105150000__plan_configuration_add_active_ddl.sql deleted file mode 100644 index 3586cd4cb45..00000000000 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20242105150000__plan_configuration_add_active_ddl.sql +++ /dev/null @@ -1,11 +0,0 @@ -ALTER TABLE plan_configuration_files ADD active boolean; -UPDATE plan_configuration_files SET active = true WHERE active IS NULL; - -ALTER TABLE plan_configuration_assumptions ADD active boolean; -UPDATE plan_configuration_assumptions SET active = true WHERE active IS NULL; - -ALTER TABLE plan_configuration_operations ADD active boolean; -UPDATE plan_configuration_operations SET active = true WHERE active IS NULL; - -ALTER TABLE plan_configuration_mapping ADD active boolean; -UPDATE plan_configuration_mapping SET active = true WHERE active IS NULL; \ No newline at end of file diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20242109141800__plan_employee_assignment_create_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20242109141800__plan_employee_assignment_create_ddl.sql new file mode 100644 index 00000000000..1e28950ca6f --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20242109141800__plan_employee_assignment_create_ddl.sql @@ -0,0 +1,19 @@ +-- Table: plan_employee_assignment +CREATE TABLE plan_employee_assignment ( + id character varying(64), + tenant_id character varying(64), + plan_configuration_id character varying(64), + employee_id character varying(64), + role character varying(64), + hierarchy_level character varying(64), + jurisdiction TEXT, + plan_configuration_name character varying(128), + additional_details JSONB, + active boolean DEFAULT true, + created_by character varying(64), + created_time bigint, + last_modified_by character varying(64), + last_modified_time bigint, + CONSTRAINT uk_plan_employee_assignment_id PRIMARY KEY (id), + FOREIGN KEY (plan_configuration_id) REFERENCES plan_configuration(id) +); diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20242110115700__alter_plan_assignee_create_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20242110115700__alter_plan_assignee_create_ddl.sql new file mode 100644 index 00000000000..584399af592 --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20242110115700__alter_plan_assignee_create_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE plan ALTER COLUMN assignee TYPE TEXT; diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20242112141500__alter plan_facility_add_boundary_ancestral_path_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20242112141500__alter plan_facility_add_boundary_ancestral_path_ddl.sql new file mode 100644 index 00000000000..0bf373ddcd7 --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20242112141500__alter plan_facility_add_boundary_ancestral_path_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE plan_facility_linkage ADD boundary_ancestral_path TEXT; \ No newline at end of file diff --git a/health-services/resource-estimation-service/CHANGELOG.md b/health-services/resource-estimation-service/CHANGELOG.md deleted file mode 100644 index e5ce4491284..00000000000 --- a/health-services/resource-estimation-service/CHANGELOG.md +++ /dev/null @@ -1,8 +0,0 @@ -# Changelog -## 1.0.0 - 2024-06-24 -#### Base Resource Estimation Service - 1. Resource Estimation Service manages file processing: validating data, calculating for files, updating plans, and integrating with campaigns. - 2. File Processing: In file processing, it processes files present in plan configuration by calculating resources. - 3. Updating Plan: It creates plans based on rows and updates those by putting them on topics that are consumed by the plan service. - 4. Integrate with Campaign Manager: After processing calculations, it also integrates resources and boundary with the Campaign Manager. - 5. Boundary and Data Validation: Validates boundaries and excel data during calculations. \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java deleted file mode 100644 index 797c9a894c3..00000000000 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.egov.processor.config; - - -import org.springframework.stereotype.Component; - - -@Component -public class ServiceConstants { - - public static final String EXTERNAL_SERVICE_EXCEPTION = "External Service threw an Exception: "; - public static final String SEARCHER_SERVICE_EXCEPTION = "Exception while fetching from searcher: "; - - public static final String ERROR_WHILE_FETCHING_FROM_MDMS = "Exception occurred while fetching category lists from mdms: "; - - public static final String TENANTID_REPLACER = "{tenantId}"; - - public static final String TENANTID = "tenantId"; - - public static final String FILESTORE_ID_REPLACER = "{fileStoreId}"; - - public static final String FILES = "files"; - - public static final String FILESTORE_ID = "fileStoreId"; - - public static final String MODULE = "module"; - - public static final String MICROPLANNING_MODULE = "microplan"; - - public static final String PROPERTIES = "properties"; - - public static final String NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE = "NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT"; - public static final String NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE = "Invalid or incorrect TenantId. No mdms data found for provided Tenant."; - - public static final String ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE = "Exception occurred while fetching plan configuration from plan service "; - - public static final String NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_CODE = "NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM"; - public static final String NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_MESSAGE = "Not able to fetch byte stream from a multipart file"; - - public static final String BOUNDARY_CODE = "boundaryCode"; - public static final String ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY = "Exception occurred while fetching plan configuration from plan service for Locality "; - - public static final String ERROR_WHILE_SEARCHING_CAMPAIGN = "Exception occurred while searching/updating campaign."; - public static final String FILE_NAME = "output.xls"; - public static final String FILE_TYPE = "boundaryWithTarget"; - public static final String FILE_TEMPLATE_IDENTIFIER = "Population"; - public static final String INPUT_IS_NOT_VALID = "File does not contain valid input for row "; - - public static final String MDMS_SCHEMA_TYPE = "type"; - public static final String MDMS_SCHEMA_SECTION = "section"; - public static final String MDMS_PLAN_MODULE_NAME = "hcm-microplanning"; - public static final String MDMS_MASTER_SCHEMAS = "Schemas"; - public static final String MDMS_CAMPAIGN_TYPE = "campaignType"; - - public static final String ERROR_WHILE_UPDATING_PLAN_CONFIG = "Exception occurred while updating plan configuration."; - - public static final String VALIDATE_STRING_REGX = "^(?!\\d+$).+$"; - public static final String VALIDATE_NUMBER_REGX = "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"; - public static final String VALIDATE_BOOLEAN_REGX = "^(?i)(true|false)$"; - - public static final String FILE_TEMPLATE = "Facilities"; - public static final String HIERARCHYTYPE_REPLACER = "{hierarchyType}"; - public static final String FILE_EXTENSION = "excel"; - - public static final String SCIENTIFIC_NOTATION_INDICATOR = "E"; - public static final String ATTRIBUTE_IS_REQUIRED ="isRequired"; - public static final int DEFAULT_SCALE=2; - - public static final String MDMS_LOCALE_SEARCH_MODULE ="rainmaker-microplanning,rainmaker-boundary-undefined,rainmaker-hcm-admin-schemas"; - public static final String ERROR_WHILE_SEARCHING_LOCALE = "Exception occurred while searching locale. "; - public static final String MDMS_MASTER_COMMON_CONSTANTS = "CommonConstants"; - -} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java deleted file mode 100644 index 32a5c0b4ccc..00000000000 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.egov.processor.web.models; - -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.math.BigDecimal; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -@Validated -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class MetricDetail { - - @JsonProperty("value") - @NotNull - private BigDecimal metricValue = null; - - @JsonProperty("comparator") - @NotNull - @Size(min = 1, max = 64) - private String metricComparator = null; - - @JsonProperty("unit") - @NotNull - @Size(min = 1, max = 128) - private String metricUnit = null; - -} diff --git a/health-services/resource-generator/CHANGELOG.md b/health-services/resource-generator/CHANGELOG.md new file mode 100644 index 00000000000..f56811de913 --- /dev/null +++ b/health-services/resource-generator/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +## 1.0.0 - 2024-12-03 +#### Resource Generator Service +The Resource Generator Service introduces comprehensive functionalities for microplanning resource estimation and campaign integration: + +1. File Processing: Supports Excel, Shapefiles, and GeoJSON for resource estimation and validates input data against the plan configuration. +2. Resource Estimation: Calculates resources using predefined formulas and updates plans by publishing data to relevant topics. +3. Boundary Validation: Ensures boundary integrity and validates data during resource calculations. +4. Process Triggers: Automates Plan-Facility creation, Census data creation, and Plan generation based on file uploads and validations. +5. Campaign Integration: Integrates estimated resources and boundaries with the Campaign Manager for streamlined planning. +6. Result Upload: Automates the upload of approved resource sheets to the filestore and updates plan configurations. +7. HCM Integration: Updates project factory with resource estimates for accurate campaign planning. \ No newline at end of file diff --git a/health-services/resource-estimation-service/LOCALSETUP.md b/health-services/resource-generator/LOCALSETUP.md similarity index 100% rename from health-services/resource-estimation-service/LOCALSETUP.md rename to health-services/resource-generator/LOCALSETUP.md diff --git a/health-services/resource-estimation-service/README.md b/health-services/resource-generator/README.md similarity index 100% rename from health-services/resource-estimation-service/README.md rename to health-services/resource-generator/README.md diff --git a/health-services/resource-estimation-service/pom.xml b/health-services/resource-generator/pom.xml similarity index 95% rename from health-services/resource-estimation-service/pom.xml rename to health-services/resource-generator/pom.xml index c73dd06629d..33ac3c4c7d6 100644 --- a/health-services/resource-estimation-service/pom.xml +++ b/health-services/resource-generator/pom.xml @@ -1,7 +1,7 @@ 4.0.0 org.egov - resource-estimation-service + resource-generator jar file-processor-utility 1.0.0 @@ -98,6 +98,12 @@ tracer 2.9.0-SNAPSHOT + + org.egov.services + services-common + 2.9.0-SNAPSHOT + compile + org.egov mdms-client diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java b/health-services/resource-generator/src/main/java/org/egov/processor/Main.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java rename to health-services/resource-generator/src/main/java/org/egov/processor/Main.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/Configuration.java similarity index 54% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java rename to health-services/resource-generator/src/main/java/org/egov/processor/config/Configuration.java index 12ce0667abd..c652337ba28 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/config/Configuration.java @@ -11,6 +11,8 @@ import lombok.NoArgsConstructor; import lombok.Setter; +import java.util.List; + @Component @Data @Import({ TracerConfiguration.class }) @@ -27,12 +29,18 @@ public class Configuration { @Value("${egov.mdms.search.endpoint}") private String mdmsEndPoint; + @Value("${egov.mdms.search.v2.endpoint}") + private String mdmsV2EndPoint; + @Value("${egov.plan.config.host}") private String planConfigHost; @Value("${egov.plan.config.endpoint}") private String planConfigEndPoint; + @Value("${egov.plan.search.endpoint}") + private String planSearchEndPoint; + // Filestore @Value("${egov.filestore.service.host}") @@ -53,18 +61,18 @@ public class Configuration { @Value("${egov.project.factory.update.endpoint}") private String campaignIntegrationUpdateEndPoint; + @Value("${egov.project.factory.data.create.endpoint}") + private String campaignIntegrationDataCreateEndPoint; + + @Value("${egov.project.factory.fetch.from.microplan.endpoint}") + private String campaignIntegrationFetchFromMicroplanEndPoint; + @Value("${egov.project.factory.host}") private String projectFactoryHostEndPoint; - @Value("${resource.microplan.create.topic}") - private String resourceMicroplanCreateTopic; - @Value("${integrate.with.admin.console}") private boolean isIntegrateWithAdminConsole; - @Value("${resource.update.plan.config.consumer.topic}") - private String resourceUpdatePlanConfigConsumerTopic; - @Value("${egov.boundary.service.host}") private String egovBoundaryServiceHost; @@ -77,4 +85,51 @@ public class Configuration { @Value("${egov.locale.search.endpoint}") private String egovLocaleSearchEndpoint; + //trigger statuses + @Value("${plan.config.trigger.plan.estimates.status}") + private String planConfigTriggerPlanEstimatesStatus; + + @Value("${plan.config.trigger.census.records.status}") + private String planConfigTriggerCensusRecordsStatus; + + @Value("${plan.config.update.plan.estimates.into.output.file.status}") + private String planConfigUpdatePlanEstimatesIntoOutputFileStatus; + + @Value("${plan.config.trigger.plan.facility.mappings.status}") + private String planConfigTriggerPlanFacilityMappingsStatus; + + //Kafka topics for creating or updating records in dependent microservices + @Value("${resource.microplan.create.topic}") + private String resourceMicroplanCreateTopic; + + @Value("${resource.update.plan.config.consumer.topic}") + private String resourceUpdatePlanConfigConsumerTopic; + + @Value("${resource.census.create.topic}") + private String resourceCensusCreateTopic; + + //Default + @Value("${resource.default.offset}") + private Integer defaultOffset; + + @Value("${resource.default.limit}") + private Integer defaultLimit; + + //census additonal field configs + @Value("${census.additional.field.override.keys}") + public List censusAdditionalFieldOverrideKeys; + + @Value("${census.additional.field.prefix.append.keys}") + public List censusAdditionalPrefixAppendKeys; + + @Value("${census.additional.field.show.on.ui.false.keys}") + public List censusAdditionalFieldShowOnUIFalseKeys; + + //census host + @Value("${egov.census.host}") + private String censusHost; + + @Value("${egov.census.search.endpoint}") + private String censusSearchEndPoint; + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/MainConfiguration.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java rename to health-services/resource-generator/src/main/java/org/egov/processor/config/MainConfiguration.java diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java new file mode 100644 index 00000000000..7200f29cecc --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -0,0 +1,123 @@ +package org.egov.processor.config; + + +import org.springframework.stereotype.Component; + + +@Component +public class ServiceConstants { + + public static final String EXTERNAL_SERVICE_EXCEPTION = "External Service threw an Exception: "; + public static final String SEARCHER_SERVICE_EXCEPTION = "Exception while fetching from searcher: "; + + public static final String ERROR_WHILE_FETCHING_FROM_MDMS = "Exception occurred while fetching category lists from mdms: "; + + public static final String ERROR_WHILE_FETCHING_FROM_CENSUS = "Exception occurred while fetching records from census: "; + + public static final String TENANTID_REPLACER = "{tenantId}"; + + public static final String TENANTID = "tenantId"; + + public static final String FILESTORE_ID_REPLACER = "{fileStoreId}"; + + public static final String FILES = "files"; + + public static final String FILESTORE_ID = "fileStoreId"; + + public static final String MODULE = "module"; + + public static final String MICROPLANNING_MODULE = "microplan"; + + public static final String NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE = "NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT"; + public static final String NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE = "Invalid or incorrect TenantId. No mdms data found for provided Tenant."; + + public static final String ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE = "Exception occurred while fetching plan configuration from plan service "; + + public static final String NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_CODE = "NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM"; + public static final String NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_MESSAGE = "Not able to fetch byte stream from a multipart file"; + + public static final String FILE_NOT_FOUND_CODE = "FILE_NOT_FOUND"; + public static final String FILE_NOT_FOUND_MESSAGE = "No file with the specified templateIdentifier found - "; + + public static final String UNABLE_TO_CREATE_ADDITIONAL_DETAILS_CODE = "UNABLE_TO_CREATE_ADDITIONAL_DETAILS"; + public static final String UNABLE_TO_CREATE_ADDITIONAL_DETAILS_MESSAGE = "Unable to create additional details for facility creation."; + + public static final String NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_CODE = "NO_PLAN_FOUND_FOR_GIVEN_DETAILS"; + public static final String NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_MESSAGE = "Census records do not exists for the given details: "; + + public static final String NO_PLAN_FOUND_FOR_GIVEN_DETAILS_CODE = "NO_PLAN_FOUND_FOR_GIVEN_DETAILS"; + public static final String NO_PLAN_FOUND_FOR_GIVEN_DETAILS_MESSAGE = "Plan records do not exists for the given details: "; + + public static final String BOUNDARY_CODE = "HCM_ADMIN_CONSOLE_BOUNDARY_CODE"; + public static final String TOTAL_POPULATION = "HCM_ADMIN_CONSOLE_TOTAL_POPULATION"; + + public static final String ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY = "Exception occurred while fetching plan configuration from plan service for Locality "; + public static final String ERROR_WHILE_PUSHING_TO_PLAN_SERVICE_FOR_LOCALITY = "Exception occurred while fetching plan configuration from plan service for Locality "; + public static final String ERROR_WHILE_SEARCHING_CAMPAIGN = "Exception occurred while searching/updating campaign."; + public static final String ERROR_WHILE_DATA_CREATE_CALL = "Exception occurred while creating data for campaign - "; + public static final String ERROR_WHILE_CALLING_MICROPLAN_API = + "Unexpected error while calling fetch from Microplan API for plan config Id: "; + + public static final String FILE_NAME = "output.xls"; + public static final String FILE_TYPE = "boundaryWithTarget"; + public static final String FILE_TEMPLATE_IDENTIFIER_POPULATION = "Population"; + public static final String FILE_TEMPLATE_IDENTIFIER_FACILITY = "Facilities"; + public static final String INPUT_IS_NOT_VALID = "File does not contain valid input for row "; + + public static final String MDMS_SCHEMA_TYPE = "type"; + public static final String MDMS_SCHEMA_SECTION = "section"; + public static final String MDMS_PLAN_MODULE_NAME = "hcm-microplanning"; + public static final String MDMS_MASTER_SCHEMAS = "Schemas"; + public static final String MDMS_CAMPAIGN_TYPE = "campaignType"; + public static final String MDMS_SCHEMA_ADMIN_SCHEMA = "adminSchema"; + public static final String MDMS_ADMIN_CONSOLE_MODULE_NAME = "HCM-ADMIN-CONSOLE"; + public static final String BOUNDARY = "boundary"; + public static final String DOT_SEPARATOR = "."; + public static final String MICROPLAN_PREFIX = "MP-"; + + //MDMS field Constants + public static final String DATA = "data"; + public static final String PROPERTIES = "properties"; + public static final String NUMBER_PROPERTIES = "numberProperties"; + public static final String STRING_PROPERTIES = "stringProperties"; + public static final String NAME = "name"; + + public static final String ERROR_WHILE_UPDATING_PLAN_CONFIG = "Exception occurred while updating plan configuration."; + public static final String ERROR_WHILE_SEARCHING_PLAN = "Exception occurred while search plans."; + + public static final String VALIDATE_STRING_REGX = "^(?!\\d+$).+$"; + public static final String VALIDATE_NUMBER_REGX = "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"; + public static final String VALIDATE_BOOLEAN_REGX = "^(?i)(true|false)$"; + + public static final String FILE_TEMPLATE = "Facilities"; + public static final String HIERARCHYTYPE_REPLACER = "{hierarchyType}"; + public static final String FILE_EXTENSION = "excel"; + + public static final String SCIENTIFIC_NOTATION_INDICATOR = "E"; + public static final String ATTRIBUTE_IS_REQUIRED ="isRequired"; + public static final int DEFAULT_SCALE=2; + + public static final String MDMS_LOCALE_SEARCH_MODULE ="rainmaker-microplanning,rainmaker-boundary-undefined,hcm-admin-schemas"; + public static final String ERROR_WHILE_SEARCHING_LOCALE = "Exception occurred while searching locale. "; + public static final String MDMS_MASTER_COMMON_CONSTANTS = "CommonConstants"; + + //override sheet names + public static final String HCM_ADMIN_CONSOLE_BOUNDARY_DATA = "HCM_ADMIN_CONSOLE_BOUNDARY_DATA"; + public static final String READ_ME_SHEET_NAME = "readMeSheetName"; + + //Workflow constants + public static final String WORKFLOW_ACTION_INITIATE = "INITIATE"; + public static final String WORKFLOW_COMMENTS_INITIATING_CENSUS = "Initiating census record creation"; + public static final String WORKFLOW_COMMENTS_INITIATING_ESTIMATES = "Initiating plan estimation record creation"; + + //Facility Create constants + public static final String TYPE_FACILITY = "facility"; + public static final String ACTION_CREATE = "create"; + public static final String SOURCE_KEY = "source"; + public static final String MICROPLAN_SOURCE_KEY = "microplan"; + public static final String MICROPLAN_ID_KEY = "microplanId"; + + //Census additional field constants + public static final String UPLOADED_KEY = "UPLOADED_"; + public static final String CONFIRMED_KEY = "CONFIRMED_"; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java b/health-services/resource-generator/src/main/java/org/egov/processor/kafka/PlanConsumer.java similarity index 66% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java rename to health-services/resource-generator/src/main/java/org/egov/processor/kafka/PlanConsumer.java index 2aa31907413..8b0c54a4010 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/kafka/PlanConsumer.java @@ -1,11 +1,9 @@ package org.egov.processor.kafka; import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.Collections; -import java.util.Map; import lombok.extern.slf4j.Slf4j; +import org.egov.processor.config.Configuration; import org.egov.processor.service.ResourceEstimationService; -import org.egov.processor.web.models.PlanConfiguration; import org.egov.processor.web.models.PlanConfigurationRequest; import org.egov.tracer.model.CustomException; import org.springframework.http.HttpStatus; @@ -13,6 +11,9 @@ import org.springframework.kafka.support.KafkaHeaders; import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.util.Map; @Component @Slf4j @@ -22,16 +23,22 @@ public class PlanConsumer { private ResourceEstimationService resourceEstimationService; - public PlanConsumer(ObjectMapper objectMapper, ResourceEstimationService resourceEstimationService) { + private Configuration config; + + public PlanConsumer(ObjectMapper objectMapper, ResourceEstimationService resourceEstimationService, Configuration config) { this.objectMapper = objectMapper; this.resourceEstimationService = resourceEstimationService; + this.config = config; } @KafkaListener(topics = { "${plan.config.consumer.kafka.save.topic}", "${plan.config.consumer.kafka.update.topic}" }) public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { PlanConfigurationRequest planConfigurationRequest = objectMapper.convertValue(consumerRecord, PlanConfigurationRequest.class); - if (planConfigurationRequest.getPlanConfiguration().getStatus().equals(PlanConfiguration.StatusEnum.GENERATED)) { + if (!ObjectUtils.isEmpty(planConfigurationRequest.getPlanConfiguration().getWorkflow()) && (planConfigurationRequest.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerPlanEstimatesStatus()) + || planConfigurationRequest.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerCensusRecordsStatus()) + || planConfigurationRequest.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerPlanFacilityMappingsStatus()) + || planConfigurationRequest.getPlanConfiguration().getStatus().equals(config.getPlanConfigUpdatePlanEstimatesIntoOutputFileStatus()))) { resourceEstimationService.estimateResources(planConfigurationRequest); log.info("Successfully estimated resources for plan."); } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java b/health-services/resource-generator/src/main/java/org/egov/processor/kafka/Producer.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java rename to health-services/resource-generator/src/main/java/org/egov/processor/kafka/Producer.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java b/health-services/resource-generator/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java rename to health-services/resource-generator/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java similarity index 74% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java rename to health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java index ee005cd81c8..32f579e00ff 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java @@ -1,36 +1,19 @@ package org.egov.processor.service; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.egov.processor.config.Configuration; import org.egov.processor.config.ServiceConstants; -import org.egov.processor.util.BoundaryUtil; -import org.egov.processor.util.CalculationUtil; -import org.egov.processor.util.CampaignIntegrationUtil; -import org.egov.processor.util.FilestoreUtil; -import org.egov.processor.util.LocaleUtil; -import org.egov.processor.util.MdmsUtil; -import org.egov.processor.util.ParsingUtil; -import org.egov.processor.util.PlanUtil; +import org.egov.processor.util.*; +import org.egov.processor.web.models.*; import org.egov.processor.web.models.Locale; -import org.egov.processor.web.models.LocaleResponse; -import org.egov.processor.web.models.Operation; -import org.egov.processor.web.models.PlanConfiguration; -import org.egov.processor.web.models.PlanConfiguration.StatusEnum; -import org.egov.processor.web.models.PlanConfigurationRequest; -import org.egov.processor.web.models.ResourceMapping; import org.egov.processor.web.models.boundary.BoundarySearchResponse; import org.egov.processor.web.models.boundary.EnrichedBoundary; import org.egov.processor.web.models.campaignManager.Boundary; @@ -40,13 +23,16 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; +import static org.egov.processor.config.ServiceConstants.HCM_ADMIN_CONSOLE_BOUNDARY_DATA; +import static org.egov.processor.config.ServiceConstants.READ_ME_SHEET_NAME; @Slf4j @Service @@ -72,9 +58,15 @@ public class ExcelParser implements FileParser { private LocaleUtil localeUtil; + private CensusUtil censusUtil; + + private EnrichmentUtil enrichmentUtil; + + private PlanConfigurationUtil planConfigurationUtil; + public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, FilestoreUtil filestoreUtil, - CalculationUtil calculationUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, - Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil,LocaleUtil localeUtil) { + CalculationUtil calculationUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, + Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil, LocaleUtil localeUtil, CensusUtil censusUtil, EnrichmentUtil enrichmentUtil, PlanConfigurationUtil planConfigurationUtil) { this.objectMapper = objectMapper; this.parsingUtil = parsingUtil; this.filestoreUtil = filestoreUtil; @@ -85,7 +77,10 @@ public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, Filestore this.mdmsUtil = mdmsUtil; this.boundaryUtil = boundaryUtil; this.localeUtil = localeUtil; - } + this.censusUtil = censusUtil; + this.enrichmentUtil = enrichmentUtil; + this.planConfigurationUtil = planConfigurationUtil; + } /** * Parses file data, extracts information from the file, and processes it. @@ -99,7 +94,7 @@ public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, Filestore */ @Override public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, - Object campaignResponse) { + Object campaignResponse) { PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); byte[] byteArray = filestoreUtil.getFile(planConfig.getTenantId(), fileStoreId); File file = parsingUtil.convertByteArrayToFile(byteArray, ServiceConstants.FILE_EXTENSION); @@ -108,7 +103,8 @@ public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, S throw new CustomException("FileNotFound", "The file with ID " + fileStoreId + " was not found in the tenant " + planConfig.getTenantId()); } - return processExcelFile(planConfigurationRequest, file, fileStoreId, campaignResponse); + processExcelFile(planConfigurationRequest, file, fileStoreId, campaignResponse); + return null; } /** @@ -122,20 +118,17 @@ public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, S * @param fileStoreId The ID of the file in the file store. * @param campaignResponse The response object to be updated with * processed data. - * @return The ID of the uploaded file. */ - private String processExcelFile(PlanConfigurationRequest planConfigurationRequest, File file, String fileStoreId, + private void processExcelFile(PlanConfigurationRequest planConfigurationRequest, File file, String fileStoreId, Object campaignResponse) { - PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); try (Workbook workbook = new XSSFWorkbook(file)) { List campaignBoundaryList = new ArrayList<>(); List campaignResourcesList = new ArrayList<>(); DataFormatter dataFormatter = new DataFormatter(); - processSheets(planConfigurationRequest, fileStoreId, campaignResponse, planConfig, workbook, - campaignBoundaryList, campaignResourcesList, dataFormatter); - String uploadedFileStoreId = uploadFileAndIntegrateCampaign(planConfigurationRequest, campaignResponse, - planConfig, workbook, campaignBoundaryList, campaignResourcesList); - return uploadedFileStoreId; + processSheets(planConfigurationRequest, fileStoreId, campaignResponse, workbook, + campaignBoundaryList, dataFormatter); + uploadFileAndIntegrateCampaign(planConfigurationRequest, campaignResponse, + workbook, campaignBoundaryList, campaignResourcesList); } catch (FileNotFoundException e) { log.error("File not found: {}", e.getMessage()); throw new CustomException("FileNotFound", "The specified file was not found."); @@ -154,28 +147,26 @@ private String processExcelFile(PlanConfigurationRequest planConfigurationReques * * @param planConfigurationRequest The request containing configuration details including tenant ID. * @param campaignResponse The response object containing campaign details. - * @param planConfig The configuration details specific to the plan. * @param workbook The workbook containing data to be uploaded and integrated. * @param campaignBoundaryList List of boundary objects related to the campaign. * @param campaignResourcesList List of campaign resources to be integrated. - * @return The ID of the uploaded file in the file store. */ - private String uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigurationRequest, - Object campaignResponse, PlanConfiguration planConfig, Workbook workbook, + private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigurationRequest, + Object campaignResponse, Workbook workbook, List campaignBoundaryList, List campaignResourcesList) { File fileToUpload = null; try { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); fileToUpload = convertWorkbookToXls(workbook); - String uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); - - if (config.isIntegrateWithAdminConsole()) { - campaignIntegrationUtil.updateCampaignResources(uploadedFileStoreId, campaignResourcesList, - fileToUpload.getName()); - - campaignIntegrationUtil.updateCampaignDetails(planConfigurationRequest, campaignResponse, - campaignBoundaryList, campaignResourcesList); + if (planConfig.getStatus().equals(config.getPlanConfigTriggerPlanEstimatesStatus())) { + String uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); + planUtil.setFileStoreIdForPopulationTemplate(planConfigurationRequest, uploadedFileStoreId); + planUtil.update(planConfigurationRequest); } - return uploadedFileStoreId; + if (planConfig.getStatus().equals(config.getPlanConfigUpdatePlanEstimatesIntoOutputFileStatus()) && config.isIntegrateWithAdminConsole()) { + String uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); + campaignIntegrationUtil.updateResourcesInProjectFactory(planConfigurationRequest, uploadedFileStoreId); + } } finally { try { if (fileToUpload != null && !fileToUpload.delete()) { @@ -191,32 +182,47 @@ private String uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfi * Processes each sheet in the workbook for plan configuration data. * Validates column names, processes rows, and integrates campaign details. * - * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param request The request containing configuration details including tenant ID. * @param fileStoreId The ID of the uploaded file in the file store. * @param campaignResponse The response object containing campaign details. - * @param planConfig The configuration details specific to the plan. * @param excelWorkbook The workbook containing sheets to be processed. * @param campaignBoundaryList List of boundary objects related to the campaign. - * @param campaignResourcesList List of campaign resources to be integrated. * @param dataFormatter The data formatter for formatting cell values. */ - private void processSheets(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, - Object campaignResponse, PlanConfiguration planConfig, Workbook excelWorkbook, - List campaignBoundaryList, List campaignResourcesList, - DataFormatter dataFormatter) { - LocaleResponse localeResponse = localeUtil.searchLocale(planConfigurationRequest); - CampaignResponse campaign = parseCampaignResponse(campaignResponse); - Map attributeNameVsDataTypeMap = prepareAttributeVsIndexMap(planConfigurationRequest, - fileStoreId, campaign, planConfig); - List boundaryCodeList = getBoundaryCodeList(planConfigurationRequest, campaign, planConfig); - + private void processSheets(PlanConfigurationRequest request, String fileStoreId, + Object campaignResponse, Workbook excelWorkbook, + List campaignBoundaryList, + DataFormatter dataFormatter) { + CampaignResponse campaign = campaignIntegrationUtil.parseCampaignResponse(campaignResponse); + LocaleResponse localeResponse = localeUtil.searchLocale(request); + Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), + request.getPlanConfiguration().getTenantId()); + planConfigurationUtil.orderPlanConfigurationOperations(request); + enrichmentUtil.enrichResourceMapping(request, localeResponse, campaign.getCampaign().get(0).getProjectType(), fileStoreId); + Map attributeNameVsDataTypeMap = prepareAttributeVsIndexMap(request, + fileStoreId, campaign, request.getPlanConfiguration(), mdmsData); + + List boundaryCodeList = getBoundaryCodeList(request, campaign); + Map mappedValues = request.getPlanConfiguration().getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap( + ResourceMapping::getMappedTo, + ResourceMapping::getMappedFrom, + (existing, replacement) -> existing, + LinkedHashMap::new + )); excelWorkbook.forEach(excelWorkbookSheet -> { - if (isSheetAlloedToProcess(planConfigurationRequest, excelWorkbookSheet.getSheetName(),localeResponse)) { - Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(excelWorkbookSheet); - List columnNamesList = mapOfColumnNameAndIndex.keySet().stream().toList(); - parsingUtil.validateColumnNames(columnNamesList, planConfig, fileStoreId); - processRows(planConfigurationRequest, excelWorkbookSheet, dataFormatter, fileStoreId, - campaignBoundaryList, attributeNameVsDataTypeMap, boundaryCodeList); + if (isSheetAllowedToProcess(request, excelWorkbookSheet.getSheetName(), localeResponse)) { + if (request.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerPlanEstimatesStatus())) { + enrichmentUtil.enrichsheetWithApprovedCensusRecords(excelWorkbookSheet, request, fileStoreId, mappedValues); + processRows(request, excelWorkbookSheet, dataFormatter, fileStoreId, + campaignBoundaryList, attributeNameVsDataTypeMap, boundaryCodeList); + } else if (request.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerCensusRecordsStatus())) { + processRowsForCensusRecords(request, excelWorkbookSheet, + fileStoreId, attributeNameVsDataTypeMap, boundaryCodeList, campaign.getCampaign().get(0).getHierarchyType()); + } else if (request.getPlanConfiguration().getStatus().equals(config.getPlanConfigUpdatePlanEstimatesIntoOutputFileStatus())) { + enrichmentUtil.enrichsheetWithApprovedPlanEstimates(excelWorkbookSheet, request, fileStoreId, mappedValues); + } } }); } @@ -241,8 +247,41 @@ private void processSheets(PlanConfigurationRequest planConfigurationRequest, St */ private void processRows(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, DataFormatter dataFormatter, String fileStoreId, List campaignBoundaryList, Map attributeNameVsDataTypeMap, List boundaryCodeList) { PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + performRowLevelCalculations(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignBoundaryList, planConfig, attributeNameVsDataTypeMap, boundaryCodeList); + } + + private void processRowsForCensusRecords(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, String fileStoreId, Map attributeNameVsDataTypeMap, List boundaryCodeList, String hierarchyType) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap( + ResourceMapping::getMappedTo, + ResourceMapping::getMappedFrom, + (existing, replacement) -> existing, + LinkedHashMap::new + )); + + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, + parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); Row firstRow = null; - performRowLevelCalculations(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignBoundaryList, planConfig, attributeNameVsDataTypeMap, boundaryCodeList, firstRow); + + for (Row row : sheet) { + if (parsingUtil.isRowEmpty(row)) + continue; + + if (row.getRowNum() == 0) { + firstRow = row; + continue; + } + + validateRows(indexOfBoundaryCode, row, firstRow, attributeNameVsDataTypeMap, mappedValues, mapOfColumnNameAndIndex, + planConfigurationRequest, boundaryCodeList, sheet); + JsonNode currentRow = createFeatureNodeFromRow(row, mapOfColumnNameAndIndex); + + censusUtil.create(planConfigurationRequest, currentRow, mappedValues, hierarchyType); + } } /** @@ -250,12 +289,11 @@ private void processRows(PlanConfigurationRequest planConfigurationRequest, Shee * * @param planConfigurationRequest The request containing configuration details including tenant ID. * @param campaign The campaign response object containing campaign details. - * @param planConfig The configuration details specific to the plan. * @return A list of boundary codes corresponding to the specified hierarchy type and tenant ID. */ private List getBoundaryCodeList(PlanConfigurationRequest planConfigurationRequest, - CampaignResponse campaign, PlanConfiguration planConfig) { - BoundarySearchResponse boundarySearchResponse = boundaryUtil.search(planConfig.getTenantId(), + CampaignResponse campaign) { + BoundarySearchResponse boundarySearchResponse = boundaryUtil.search(planConfigurationRequest.getPlanConfiguration().getTenantId(), campaign.getCampaign().get(0).getHierarchyType(), planConfigurationRequest); List boundaryList = new ArrayList<>(); List boundaryCodeList = getAllBoundaryPresentforHierarchyType( @@ -272,29 +310,15 @@ private List getBoundaryCodeList(PlanConfigurationRequest planConfigurat * @param planConfig The configuration details specific to the plan. * @return A map of attribute names to their corresponding indices or data types. */ + private Map prepareAttributeVsIndexMap(PlanConfigurationRequest planConfigurationRequest, - String fileStoreId, CampaignResponse campaign, PlanConfiguration planConfig) { - Object mdmsData = mdmsUtil.fetchMdmsData(planConfigurationRequest.getRequestInfo(), - planConfigurationRequest.getPlanConfiguration().getTenantId()); + String fileStoreId, CampaignResponse campaign, PlanConfiguration planConfig, Object mdmsData) { org.egov.processor.web.models.File file = planConfig.getFiles().stream() .filter(f -> f.getFilestoreId().equalsIgnoreCase(fileStoreId)).findFirst().get(); - Map attributeNameVsDataTypeMap = mdmsUtil.filterMasterData(mdmsData.toString(), file.getInputFileType(), - file.getTemplateIdentifier(), campaign.getCampaign().get(0).getProjectType()); - return attributeNameVsDataTypeMap; + return mdmsUtil.filterMasterData(mdmsData.toString(), file.getInputFileType(), + file.getTemplateIdentifier(), campaign.getCampaign().get(0).getProjectType()); } - - /** - * Parses an object representing campaign response into a CampaignResponse object. - * - * @param campaignResponse The object representing campaign response to be parsed. - * @return CampaignResponse object parsed from the campaignResponse. - */ - private CampaignResponse parseCampaignResponse(Object campaignResponse) { - CampaignResponse campaign = null; - campaign = objectMapper.convertValue(campaignResponse, CampaignResponse.class); - return campaign; - } /** * Performs row-level calculations and processing on each row in the sheet. @@ -309,14 +333,23 @@ private CampaignResponse parseCampaignResponse(Object campaignResponse) { * @param planConfig The configuration details specific to the plan. * @param attributeNameVsDataTypeMap Mapping of attribute names to their data types. * @param boundaryCodeList List of boundary codes. - * @param firstRow The first row of the sheet. */ private void performRowLevelCalculations(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, DataFormatter dataFormatter, String fileStoreId, List campaignBoundaryList, - PlanConfiguration planConfig, Map attributeNameVsDataTypeMap, List boundaryCodeList, - Row firstRow) { + PlanConfiguration planConfig, Map attributeNameVsDataTypeMap, List boundaryCodeList) { + Row firstRow = null; + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap(ResourceMapping::getMappedTo, ResourceMapping::getMappedFrom)); + Map assumptionValueMap = calculationUtil + .convertAssumptionsToMap(planConfig.getAssumptions()); + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + + Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, + parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); + for (Row row : sheet) { - if(isRowEmpty(row)) + if(parsingUtil.isRowEmpty(row)) continue; if (row.getRowNum() == 0) { @@ -325,48 +358,18 @@ private void performRowLevelCalculations(PlanConfigurationRequest planConfigurat } Map resultMap = new HashMap<>(); - Map mappedValues = planConfig.getResourceMapping().stream() - .filter(f -> f.getFilestoreId().equals(fileStoreId)) - .collect(Collectors.toMap(ResourceMapping::getMappedTo, ResourceMapping::getMappedFrom)); - Map assumptionValueMap = calculationUtil - .convertAssumptionsToMap(planConfig.getAssumptions()); - Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); - - Integer indexOfBoundaryCode = campaignIntegrationUtil.getIndexOfBoundaryCode(0, - campaignIntegrationUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); validateRows(indexOfBoundaryCode, row, firstRow, attributeNameVsDataTypeMap, mappedValues, mapOfColumnNameAndIndex, planConfigurationRequest, boundaryCodeList, sheet); - JsonNode feature = createFeatureNodeFromRow(row, dataFormatter, mapOfColumnNameAndIndex); + JsonNode feature = createFeatureNodeFromRow(row, mapOfColumnNameAndIndex); performCalculationsOnOperations(sheet, planConfig, row, resultMap, mappedValues, assumptionValueMap, feature); if (config.isIntegrateWithAdminConsole()) campaignIntegrationUtil.updateCampaignBoundary(planConfig, feature, assumptionValueMap, mappedValues, mapOfColumnNameAndIndex, campaignBoundaryList, resultMap); planUtil.create(planConfigurationRequest, feature, resultMap, mappedValues); - // TODO: remove after testing - printRow(sheet, row); } } - /** - * Checks if a given row is empty. - * - * A row is considered empty if it is null or if all of its cells are empty or of type BLANK. - * - * @param row the Row to check - * @return true if the row is empty, false otherwise - */ - public static boolean isRowEmpty(Row row) { - if (row == null) { - return true; - } - for (Cell cell : row) { - if (cell != null && cell.getCellType() != CellType.BLANK) { - return false; - } - } - return true; - } /** * Performs calculations on operations for a specific row in the sheet. @@ -407,7 +410,7 @@ private void performCalculationsOnOperations(Sheet sheet, PlanConfiguration plan * * @param convertedFile The converted XLS file to upload. * @param tenantId The tenant ID for the file upload. - * @return The file store ID of the uploaded file, or null if an error occurred. + * @return The file store ID of the uploaded file, or null if an error occurred. */ private String uploadConvertedFile(File convertedFile, String tenantId) { if (convertedFile != null) { @@ -458,12 +461,10 @@ private File convertWorkbookToXls(Workbook workbook) { * Creates a JSON feature node from a row in the Excel sheet. * * @param row The row in the Excel sheet. - * @param dataFormatter The data formatter for formatting cell values. * @param columnIndexMap The mapping of column names to column indices. * @return The JSON feature node representing the row. */ - private JsonNode createFeatureNodeFromRow(Row row, DataFormatter dataFormatter, - Map columnIndexMap) { + private JsonNode createFeatureNodeFromRow(Row row, Map columnIndexMap) { ObjectNode featureNode = objectMapper.createObjectNode(); ObjectNode propertiesNode = featureNode.putObject("properties"); @@ -474,47 +475,51 @@ private JsonNode createFeatureNodeFromRow(Row row, DataFormatter dataFormatter, // Get the cell value from the row based on the columnIndex Cell cell = row.getCell(columnIndex); - String cellValue = dataFormatter.formatCellValue(cell); - - // Add the columnName and cellValue to the propertiesNode - propertiesNode.put(columnName, cellValue); - } -// System.out.println("Feature Node ---- > " + featureNode); - return featureNode; - } + if (cell == null) { + // Handle null cells if needed + propertiesNode.putNull(columnName); + continue; + } - public void printRow(Sheet sheet, Row row) { - System.out.print("Row -> "); - for (Cell cell : row) { - int columnIndex = cell.getColumnIndex(); - // String columnName = sheet.getRow(0).getCell(columnIndex).toString(); - // System.out.print("Column " + columnName + " - "); switch (cell.getCellType()) { - case STRING: - System.out.print(cell.getStringCellValue() + "\t"); - break; - case NUMERIC: - if (DateUtil.isCellDateFormatted(cell)) { - System.out.print(cell.getDateCellValue() + "\t"); - } else { - System.out.print(cell.getNumericCellValue() + "\t"); - } - break; - case BOOLEAN: - System.out.print(cell.getBooleanCellValue() + "\t"); - break; - case FORMULA: - System.out.print(cell.getCellFormula() + "\t"); - break; - case BLANK: - System.out.print("\t"); - break; - default: - System.out.print("\t"); - break; + case STRING: + propertiesNode.put(columnName, cell.getStringCellValue()); + break; + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + // Handle date values + propertiesNode.put(columnName, cell.getDateCellValue().toString()); + } else { + propertiesNode.put(columnName, BigDecimal.valueOf(cell.getNumericCellValue())); + } + break; + case BOOLEAN: + propertiesNode.put(columnName, cell.getBooleanCellValue()); + break; + case FORMULA: + // Attempt to get the cached formula result value directly + switch (cell.getCachedFormulaResultType()) { + case NUMERIC: + propertiesNode.put(columnName, BigDecimal.valueOf(cell.getNumericCellValue())); + break; + case STRING: + propertiesNode.put(columnName, cell.getStringCellValue()); + break; + case BOOLEAN: + propertiesNode.put(columnName, cell.getBooleanCellValue()); + break; + default: + propertiesNode.putNull(columnName); + break; + } + break; + default: + propertiesNode.putNull(columnName); + break; } } - System.out.println(); // Move to the next line after printing the row + + return featureNode; } /** @@ -543,13 +548,13 @@ public void validateRows(Integer indexOfBoundaryCode, Row row, Row columnHeaderR boundaryCodeList); } catch (JsonProcessingException e) { log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " at sheet - " + sheet); - planConfigurationRequest.getPlanConfiguration().setStatus(StatusEnum.INVALID_DATA); + planConfigurationRequest.getPlanConfiguration().setStatus("INVALID_DATA"); planUtil.update(planConfigurationRequest); throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " at sheet - " + sheet); } catch (CustomException customException) { log.info(customException.toString()+ "at sheet - " + sheet.getSheetName()); - planConfigurationRequest.getPlanConfiguration().setStatus(StatusEnum.INVALID_DATA); + planConfigurationRequest.getPlanConfiguration().setStatus("INVALID_DATA"); planUtil.update(planConfigurationRequest); throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), customException.getMessage()+ "at sheet - " + sheet.getSheetName()); @@ -718,13 +723,14 @@ public List getAllBoundaryPresentforHierarchyType(List * @throws JsonMappingException If there's an issue mapping JSON response to Java objects. * @throws JsonProcessingException If there's an issue processing JSON during conversion. */ - private boolean isSheetAlloedToProcess(PlanConfigurationRequest planConfigurationRequest, String sheetName,LocaleResponse localeResponse) { + private boolean isSheetAllowedToProcess(PlanConfigurationRequest planConfigurationRequest, String sheetName, LocaleResponse localeResponse) { Map mdmsDataConstants = mdmsUtil.fetchMdmsDataForCommonConstants( planConfigurationRequest.getRequestInfo(), planConfigurationRequest.getPlanConfiguration().getTenantId()); - String value = (String) mdmsDataConstants.get("readMeSheetName"); + for (Locale locale : localeResponse.getMessages()) { - if ((locale.getCode().equalsIgnoreCase(value))) { + if ((locale.getCode().equalsIgnoreCase((String) mdmsDataConstants.get(READ_ME_SHEET_NAME))) + || locale.getCode().equalsIgnoreCase(HCM_ADMIN_CONSOLE_BOUNDARY_DATA)) { if (sheetName.equals(locale.getMessage())) return false; } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/FileParser.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java rename to health-services/resource-generator/src/main/java/org/egov/processor/service/FileParser.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/GeoJsonParser.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java rename to health-services/resource-generator/src/main/java/org/egov/processor/service/GeoJsonParser.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/ResourceEstimationService.java similarity index 82% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java rename to health-services/resource-generator/src/main/java/org/egov/processor/service/ResourceEstimationService.java index c1b1ab07b7a..978633933b9 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/service/ResourceEstimationService.java @@ -1,9 +1,7 @@ package org.egov.processor.service; -import java.util.HashMap; -import java.util.Map; - +import lombok.extern.slf4j.Slf4j; import org.egov.processor.config.Configuration; import org.egov.processor.config.ServiceConstants; import org.egov.processor.repository.ServiceRequestRepository; @@ -11,10 +9,12 @@ import org.egov.processor.web.models.File; import org.egov.processor.web.models.PlanConfiguration; import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.campaignManager.CampaignResponse; import org.egov.processor.web.models.campaignManager.CampaignSearchRequest; import org.springframework.stereotype.Service; -import lombok.extern.slf4j.Slf4j; +import java.util.HashMap; +import java.util.Map; @Service @Slf4j @@ -48,7 +48,8 @@ public void estimateResources(PlanConfigurationRequest planConfigurationRequest) Map parserMap = getInputFileTypeMap(); Object campaignSearchResponse = performCampaignSearch(planConfigurationRequest); - processFiles(planConfigurationRequest, planConfiguration, parserMap, campaignSearchResponse); + processFacilityFile(planConfigurationRequest, campaignSearchResponse); + processFiles(planConfigurationRequest, planConfiguration, parserMap, campaignSearchResponse); } /** @@ -108,5 +109,21 @@ public Map getInputFileTypeMap() return parserMap; } + + /** + * Processes the facility file by parsing the campaign response and initiating + * a data creation call to the Project Factory service. + * + * @param planConfigurationRequest the request containing plan configuration details + * @param campaignResponseObject the campaign response object to be parsed + */ + public void processFacilityFile(PlanConfigurationRequest planConfigurationRequest, Object campaignResponseObject) { + if (planConfigurationRequest.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerPlanFacilityMappingsStatus())) { + CampaignResponse campaignResponse = campaignIntegrationUtil.parseCampaignResponse(campaignResponseObject); + campaignIntegrationUtil.createProjectFactoryDataCall(planConfigurationRequest, campaignResponse); + log.info("Facility Data creation successful."); + } + } + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/ShapeFileParser.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java rename to health-services/resource-generator/src/main/java/org/egov/processor/service/ShapeFileParser.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/BoundaryUtil.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/BoundaryUtil.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/CalculationUtil.java similarity index 74% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/CalculationUtil.java index d6b53891a8b..551206d9b94 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/CalculationUtil.java @@ -2,13 +2,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import org.egov.processor.config.ServiceConstants; import org.egov.processor.web.models.Assumption; import org.egov.processor.web.models.Operation; @@ -16,6 +9,13 @@ import org.egov.processor.web.models.PlanConfigurationRequest; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import static org.egov.processor.config.ServiceConstants.PROPERTIES; @@ -86,21 +86,23 @@ public void calculateResources(JsonNode jsonNode, PlanConfigurationRequest planC /** * Retrieves the input value from the JSON node based on the input and input mapping. * - * @param resultMap The map containing previous results. - * @param feature The JSON node feature. - * @param input The input key. - * @param columnName The input from mapping. + * @param resultMap The map containing previous results. + * @param feature The JSON node feature. + * @param assumptionValueMap The assumptions and their value map from plan config. + * @param input The input key. + * @param columnName The input from mapping. * @return The input value. */ - public BigDecimal getInputValueFromJsonFeature(Map resultMap, JsonNode feature, String input, String columnName) { - if (resultMap.containsKey(input)) { - return resultMap.get(input); - } else { - if (feature.get(PROPERTIES).get(columnName) != null) { + private BigDecimal getInputValueFromFeatureOrMap(JsonNode feature, Map resultMap, Map assumptionValueMap, String input, String columnName) { + // Try to fetch the value from resultMap, If not found in the resultMap, use the assumptionValueMap as a fallback + BigDecimal inputValue = resultMap.getOrDefault(input, assumptionValueMap.get(input)); + + // Try to fetch the value from the feature (if it exists) + if(ObjectUtils.isEmpty(inputValue)) { + if (feature.has(PROPERTIES) && feature.get(PROPERTIES).has(columnName)) { try { String cellValue = String.valueOf(feature.get(PROPERTIES).get(columnName)); BigDecimal value; - // Handle scientific notation if (cellValue.contains(ServiceConstants.SCIENTIFIC_NOTATION_INDICATOR)) { value = new BigDecimal(cellValue); } else { @@ -109,12 +111,12 @@ public BigDecimal getInputValueFromJsonFeature(Map resultMap } return value; } catch (NumberFormatException | NullPointerException e) { - return BigDecimal.ZERO; - } - } else { - throw new CustomException("INPUT_VALUE_NOT_FOUND", "Input value not found: " + input); + // Handle potential parsing issues + throw new CustomException("INPUT_VALUE_NOT_FOUND", "Input value not found: " + input); } } } + + return inputValue; } /** @@ -127,12 +129,18 @@ public BigDecimal getInputValueFromJsonFeature(Map resultMap * @param resultMap A map to store and update the calculated results. * @return The calculated result as a BigDecimal. */ - public BigDecimal calculateResult(Operation operation, JsonNode feature, Map mappedValues, Map assumptionValueMap, Map resultMap) - { + public BigDecimal calculateResult(Operation operation, JsonNode feature, Map mappedValues, Map assumptionValueMap, Map resultMap) { + // Fetch the input value String input = operation.getInput(); String inputFromMapping = mappedValues.get(input); - BigDecimal inputValue = getInputValueFromJsonFeature(resultMap, feature, operation.getInput(), inputFromMapping); - BigDecimal assumptionValue = assumptionValueMap.get(operation.getAssumptionValue()); + BigDecimal inputValue = getInputValueFromFeatureOrMap(feature, resultMap, assumptionValueMap, input, inputFromMapping); + + // Fetch the assumption value with priority: feature -> resultMap -> assumptionValueMap + String assumptionKey = operation.getAssumptionValue(); + String assumptionFromMapping = mappedValues.get(assumptionKey); + BigDecimal assumptionValue = getInputValueFromFeatureOrMap(feature, resultMap, assumptionValueMap, assumptionKey, assumptionFromMapping); + + // Calculate and return the output return calculateOutputValue(inputValue, operation.getOperator(), assumptionValue); } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java similarity index 61% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java index d14b3512aef..9bfbe7cb62c 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java @@ -1,48 +1,25 @@ package org.egov.processor.util; -import static org.egov.processor.config.ServiceConstants.PROPERTIES; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; - +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; -import org.apache.poi.openxml4j.exceptions.InvalidFormatException; -import org.apache.poi.ss.usermodel.DataFormatter; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.egov.processor.config.Configuration; import org.egov.processor.config.ServiceConstants; import org.egov.processor.repository.ServiceRequestRepository; -import org.egov.processor.service.ExcelParser; import org.egov.processor.web.models.File; -import org.egov.processor.web.models.Operation; import org.egov.processor.web.models.PlanConfiguration; import org.egov.processor.web.models.PlanConfigurationRequest; -import org.egov.processor.web.models.ResourceMapping; -import org.egov.processor.web.models.campaignManager.Boundary; -import org.egov.processor.web.models.campaignManager.CampaignDetails; -import org.egov.processor.web.models.campaignManager.CampaignRequest; -import org.egov.processor.web.models.campaignManager.CampaignResources; -import org.egov.processor.web.models.campaignManager.CampaignResponse; -import org.egov.processor.web.models.campaignManager.CampaignSearchRequest; +import org.egov.processor.web.models.campaignManager.*; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.*; +import java.util.Map.Entry; -import lombok.extern.slf4j.Slf4j; +import static org.egov.processor.config.ServiceConstants.*; @Component @Slf4j @@ -51,6 +28,7 @@ public class CampaignIntegrationUtil { private ServiceRequestRepository serviceRequestRepository; private Configuration config; private ObjectMapper mapper; + private ParsingUtil parsingUtil; public CampaignIntegrationUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, ObjectMapper mapper, FilestoreUtil filestoreUtil, ParsingUtil parsingUtil) { @@ -58,6 +36,50 @@ public CampaignIntegrationUtil(ServiceRequestRepository serviceRequestRepository this.serviceRequestRepository = serviceRequestRepository; this.config = config; this.mapper = mapper; + this.parsingUtil= parsingUtil; + } + + /** + * Updates resources in the Project Factory by calling an external API with the given plan configuration + * request and file store ID. Logs the operation status. + * + * @param planConfigurationRequest The plan configuration request details. + * @param fileStoreId The file store ID to update. + * @throws CustomException if the API call fails. + */ + public void updateResourcesInProjectFactory(PlanConfigurationRequest planConfigurationRequest, String fileStoreId) { + try { + serviceRequestRepository.fetchResult( + new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationFetchFromMicroplanEndPoint()), + buildMicroplanDetailsForUpdate(planConfigurationRequest, fileStoreId)); + log.info("Updated resources file into project factory - " + fileStoreId); + } catch (Exception e) { + log.error(ERROR_WHILE_CALLING_MICROPLAN_API + planConfigurationRequest.getPlanConfiguration().getId(), e); + throw new CustomException(ERROR_WHILE_CALLING_MICROPLAN_API, e.toString()); + } + + } + + /** + * Builds a campaign request object for updating campaign details based on the provided plan configuration request and campaign response. + * + * @param planConfigurationRequest The plan configuration request containing necessary information for updating the campaign. + * @param fileStoreId The filestoreId with calculated resources + * @return The microplan details request object built for updating resource filestore id. + */ + private MicroplanDetailsRequest buildMicroplanDetailsForUpdate(PlanConfigurationRequest planConfigurationRequest, String fileStoreId) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + + MicroplanDetails microplanDetails = MicroplanDetails.builder() + .tenantId(planConfig.getTenantId()) + .planConfigurationId(planConfig.getId()) + .campaignId(planConfig.getCampaignId()) + .resourceFilestoreId(fileStoreId).build(); + + return MicroplanDetailsRequest.builder() + .microplanDetails(microplanDetails) + .requestInfo(planConfigurationRequest.getRequestInfo()).build(); + } /** @@ -83,7 +105,28 @@ public void updateCampaignDetails(PlanConfigurationRequest planConfigurationRequ log.info("Campaign Integration successful."); } catch (Exception e) { log.error(ServiceConstants.ERROR_WHILE_SEARCHING_CAMPAIGN - + planConfigurationRequest.getPlanConfiguration().getExecutionPlanId(), e); + + planConfigurationRequest.getPlanConfiguration().getCampaignId(), e); + throw new CustomException("Failed to update campaign details in CampaignIntegration class within method updateCampaignDetails.", e.toString()); + } + } + + /** + * Sends a data creation request to the Project Factory service using the provided + * plan and campaign details. + * + * @param planConfigurationRequest the plan configuration request containing campaign data + * @param campaignResponse the response with additional campaign information + * @throws CustomException if the data creation call fails + */ + public void createProjectFactoryDataCall(PlanConfigurationRequest planConfigurationRequest, CampaignResponse campaignResponse) { + try { + serviceRequestRepository.fetchResult( + new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationDataCreateEndPoint()), + buildResourceDetailsObjectForFacilityCreate(planConfigurationRequest, campaignResponse)); + log.info("Campaign Data create successful."); + } catch (Exception e) { + log.error(ServiceConstants.ERROR_WHILE_DATA_CREATE_CALL + + planConfigurationRequest.getPlanConfiguration().getCampaignId(), e); throw new CustomException("Failed to update campaign details in CampaignIntegration class within method updateCampaignDetails.", e.toString()); } } @@ -123,6 +166,42 @@ private CampaignRequest buildCampaignRequestForUpdate(PlanConfigurationRequest p } + /** + * Builds a {@link ResourceDetailsRequest} object for facility creation using the provided + * plan configuration and campaign details. + * + * @param planConfigurationRequest the request containing plan configuration data + * @param campaignResponse the campaign response with additional data + * @return a {@link ResourceDetailsRequest} for facility creation + * @throws CustomException if the required facility file is not found + */ + private ResourceDetailsRequest buildResourceDetailsObjectForFacilityCreate(PlanConfigurationRequest planConfigurationRequest, + CampaignResponse campaignResponse) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + + String facilityFilestoreId = String.valueOf(planConfig.getFiles().stream() + .filter(file -> FILE_TEMPLATE_IDENTIFIER_FACILITY.equals(file.getTemplateIdentifier())) + .map(File::getFilestoreId) + .findFirst() + .orElseThrow(() -> new CustomException(FILE_NOT_FOUND_CODE, FILE_NOT_FOUND_MESSAGE + FILE_TEMPLATE_IDENTIFIER_FACILITY))); + + ResourceDetails resourceDetails = ResourceDetails.builder() + .type(TYPE_FACILITY) + .hierarchyType(campaignResponse.getCampaign().get(0).getHierarchyType()) + .tenantId(planConfig.getTenantId()) + .fileStoreId(facilityFilestoreId) + .action(ACTION_CREATE) + .campaignId(planConfig.getCampaignId()) + .additionalDetails(createAdditionalDetailsforFacilityCreate(MICROPLAN_SOURCE_KEY, planConfig.getId())) + .build(); + + return ResourceDetailsRequest.builder() + .requestInfo(planConfigurationRequest.getRequestInfo()) + .resourceDetails(resourceDetails) + .build(); + + } + /** * Updates campaign boundary based on the provided plan configuration, feature, assumption values, mapped values, column index map, boundary list, and result map. * @@ -143,29 +222,13 @@ public void updateCampaignBoundary(PlanConfiguration planConfig, JsonNode featur boolean validToAdd = false; Integer indexValue = 0; Boundary boundary = new Boundary(); - List> sortedColumnList = sortColumnByIndex(mapOfColumnNameAndIndex); - indexValue = getIndexOfBoundaryCode(indexValue, sortedColumnList, mappedValues); + List> sortedColumnList = parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex); + indexValue = parsingUtil.getIndexOfBoundaryCode(indexValue, sortedColumnList, mappedValues); prepareBoundary(indexOfType, indexValue, sortedColumnList, feature, boundary, mappedValues); if (isValidToAdd(boundaryList, resultMap, validToAdd, boundary)) boundaryList.add(boundary); } - /** - * Retrieves the index value of the boundary code from the sorted column list based on the mapped values. - * - * @param indexValue The initial index value. - * @param sortedColumnList The sorted list of column names and indices. - * @param mappedValues The map containing mapped values. - * @return The index value of the boundary code. - */ - public Integer getIndexOfBoundaryCode(Integer indexValue, List> sortedColumnList,Map mappedValues) { - for (Map.Entry entry : sortedColumnList) { - if (entry.getKey().equals(mappedValues.get(ServiceConstants.BOUNDARY_CODE))) { - indexValue = entry.getValue(); - } - } - return indexValue; - } /** * Prepares a campaign boundary based on the provided index values, sorted column list, feature, and mapped values. @@ -219,22 +282,7 @@ private boolean isValidToAdd(List boundaryList, Map> sortColumnByIndex(Map mapOfColumnNameAndIndex) { - List> sortedColumnList = new ArrayList<>(mapOfColumnNameAndIndex.entrySet()); - Collections.sort(sortedColumnList, new Comparator>() { - @Override - public int compare(Map.Entry o1, Map.Entry o2) { - return o1.getValue().compareTo(o2.getValue()); - } - }); - return sortedColumnList; - } + /** * Retrieves the value of the boundary code from the feature JSON node based on the mapped values. @@ -279,9 +327,35 @@ public CampaignSearchRequest buildCampaignRequestForSearch(PlanConfigurationRequ PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); List id = new ArrayList(); - id.add(planConfig.getExecutionPlanId()); + id.add(planConfig.getCampaignId()); return CampaignSearchRequest.builder().requestInfo(planConfigurationRequest.getRequestInfo()) .campaignDetails(CampaignDetails.builder().ids(id).tenantId(planConfig.getTenantId()).build()).build(); } + + /** + * Parses an object representing campaign response into a CampaignResponse object. + * + * @param campaignResponse The object representing campaign response to be parsed. + * @return CampaignResponse object parsed from the campaignResponse. + */ + public CampaignResponse parseCampaignResponse(Object campaignResponse) { + CampaignResponse campaign = null; + campaign = mapper.convertValue(campaignResponse, CampaignResponse.class); + return campaign; + } + + public JsonNode createAdditionalDetailsforFacilityCreate(String source, String microplanId) { + try { + // Create a map to hold the additional details + Map additionalDetailsMap = new HashMap<>(); + additionalDetailsMap.put(SOURCE_KEY, source); + additionalDetailsMap.put(MICROPLAN_ID_KEY, microplanId); + + // Convert the map to a JsonNode + return mapper.valueToTree(additionalDetailsMap); + } catch (Exception e) { + throw new CustomException(UNABLE_TO_CREATE_ADDITIONAL_DETAILS_CODE, UNABLE_TO_CREATE_ADDITIONAL_DETAILS_MESSAGE);// Or throw a custom exception + } + } } diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/CensusUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/CensusUtil.java new file mode 100644 index 00000000000..2e79ff60af5 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/CensusUtil.java @@ -0,0 +1,191 @@ +package org.egov.processor.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.Workflow; +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.kafka.Producer; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.census.*; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.egov.processor.config.ServiceConstants.*; + +@Component +@Slf4j +public class CensusUtil { + + private ServiceRequestRepository serviceRequestRepository; + + private Configuration config; + + private Producer producer; + + private ParsingUtil parsingUtil; + + private ObjectMapper mapper; + + public CensusUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, Producer producer, ParsingUtil parsingUtil, ObjectMapper objectMapper) { + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.producer = producer; + this.parsingUtil = parsingUtil; + this.mapper = objectMapper; + } + + /** + * Creates and pushes a CensusRequest based on the provided plan configuration, feature JSON node, and mapped values. + * + * @param planConfigurationRequest The plan configuration request with the necessary details. + * @param feature The JSON node containing feature data for the census. + * @param mappedValues A map of property names to their values from the feature node. + * @param heirarchyType The type of hierarchy to be used in the census. + */ + public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map mappedValues, String heirarchyType) { + CensusRequest censusRequest = buildCensusRequest(planConfigurationRequest, feature, mappedValues, heirarchyType); + try { + log.info("Census request - " + censusRequest.getCensus()); + producer.push(config.getResourceCensusCreateTopic(), censusRequest); + } catch (Exception e) { + log.error(ERROR_WHILE_PUSHING_TO_PLAN_SERVICE_FOR_LOCALITY + censusRequest.getCensus().getBoundaryCode(), e); + } + } + + /** + * Builds and returns a CensusRequest using the provided plan configuration, feature JSON node, and mapped values. + * + * @param planConfigurationRequest The plan configuration request containing configuration details. + * @param feature The feature JSON node containing property values. + * @param mappedValues The mapped values for extracting properties. + * @param heirarchyType The hierarchy type of the census. + * @return A constructed CensusRequest object with populated details. + */ + private CensusRequest buildCensusRequest(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map mappedValues, String heirarchyType) { + + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + return CensusRequest.builder() + .census(Census.builder() + .tenantId(planConfig.getTenantId()) + .hierarchyType(heirarchyType) + .boundaryCode((String) parsingUtil.extractMappedValueFromFeatureForAnInput(ServiceConstants.BOUNDARY_CODE, feature, mappedValues)) + .type(Census.TypeEnum.PEOPLE) + .facilityAssigned(Boolean.FALSE) + .partnerAssignmentValidationEnabled(Boolean.TRUE) + .totalPopulation((BigDecimal) parsingUtil.extractMappedValueFromFeatureForAnInput(ServiceConstants.TOTAL_POPULATION, feature, mappedValues)) + .workflow(Workflow.builder().action(WORKFLOW_ACTION_INITIATE).build()) + .source(planConfig.getId()) + .additionalFields(enrichAdditionalField(feature, mappedValues)).build()) + .requestInfo(planConfigurationRequest.getRequestInfo()).build(); + + } + + /** + * Enriches and returns additional details by extracting values from the feature JSON node based on the provided mappings. + * + * @param feature The feature JSON node containing property values. + * @param mappedValues The mapped values for extracting properties. + * @return A map containing enriched additional details based on the extracted values. + */ + public List enrichAdditionalField(JsonNode feature, Map mappedValues) { + // Initialize orderCounter inside the function + List additionalFieldList = new ArrayList<>(); + int orderCounter = 1; + + for (String key : mappedValues.keySet()) { + // Skip keys in the override list + if (config.getCensusAdditionalFieldOverrideKeys().contains(key)) + continue; + + // Get the corresponding value from the feature JsonNode + Object valueFromRow = parsingUtil.extractMappedValueFromFeatureForAnInput(key, feature, mappedValues); + + // Check if the value exists in the JSON + if (!ObjectUtils.isEmpty(valueFromRow)) { + // Add additional fields with "UPLOADED" and "CONFIRMED" prefixes if key is in override list + if (config.getCensusAdditionalPrefixAppendKeys().contains(key)) { + AdditionalField uploadedField = AdditionalField.builder() + .key(UPLOADED_KEY + key) + .value((BigDecimal) valueFromRow) + .editable(Boolean.FALSE) + .showOnUi(Boolean.TRUE) + .order(orderCounter++) // Increment for "UPLOADED" field + .build(); + additionalFieldList.add(uploadedField); + + AdditionalField confirmedField = AdditionalField.builder() + .key(CONFIRMED_KEY + key) + .value((BigDecimal) valueFromRow) + .editable(Boolean.TRUE) + .showOnUi(Boolean.TRUE) + .order(orderCounter++) // Increment for "CONFIRMED" field + .build(); + additionalFieldList.add(confirmedField); + } else { + AdditionalField additionalField = AdditionalField.builder() + .key(key) + .value((BigDecimal) valueFromRow) + .order(orderCounter++) // Use and increment the local orderCounter + .build(); + if(config.getCensusAdditionalFieldShowOnUIFalseKeys().contains(key)) { + additionalField.setShowOnUi(Boolean.FALSE); + additionalField.setEditable(Boolean.FALSE); + } else { + additionalField.setShowOnUi(Boolean.TRUE); + additionalField.setEditable(Boolean.TRUE); + } + additionalFieldList.add(additionalField); + } + } + } + + return additionalFieldList; + } + + /** + * This method fetches data from Census based on the given census search request. + * + * @param searchRequest The census search request containing the search criteria. + * @return returns the census response. + */ + public CensusResponse fetchCensusRecords(CensusSearchRequest searchRequest) { + + // Get census search uri + String uri = getCensusUri().toString(); + + CensusResponse censusResponse = null; + try { + Object response = serviceRequestRepository.fetchResult(new StringBuilder(uri), searchRequest); + censusResponse = mapper.convertValue(response, CensusResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_CENSUS, e); + } + + if (CollectionUtils.isEmpty(censusResponse.getCensus())) { + throw new CustomException(NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_CODE, NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_MESSAGE); + } + + return censusResponse; + } + + /** + * Builds the census search uri. + * + * @return returns the complete uri for census search. + */ + private StringBuilder getCensusUri() { + return new StringBuilder().append(config.getCensusHost()).append(config.getCensusSearchEndPoint()); + } + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java new file mode 100644 index 00000000000..bb28c99f0b2 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java @@ -0,0 +1,295 @@ +package org.egov.processor.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.egov.common.utils.UUIDEnrichmentUtil; +import org.egov.processor.config.Configuration; +import org.egov.processor.web.PlanResponse; +import org.egov.processor.web.PlanSearchCriteria; +import org.egov.processor.web.PlanSearchRequest; +import org.egov.processor.web.models.*; +import org.egov.processor.web.models.census.Census; +import org.egov.processor.web.models.census.CensusResponse; +import org.egov.processor.web.models.census.CensusSearchCriteria; +import org.egov.processor.web.models.census.CensusSearchRequest; +import org.egov.processor.web.models.mdmsV2.Mdms; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.processor.config.ServiceConstants.*; + +@Component +@Slf4j +public class EnrichmentUtil { + + private MdmsV2Util mdmsV2Util; + + private LocaleUtil localeUtil; + + private ParsingUtil parsingUtil; + + private CensusUtil censusUtil; + + private PlanUtil planUtil; + + private Configuration config; +// private MultiStateInstanceUtil centralInstanceUtil; + + public EnrichmentUtil(MdmsV2Util mdmsV2Util, LocaleUtil localeUtil, ParsingUtil parsingUtil, CensusUtil censusUtil, PlanUtil planUtil, Configuration config) { + this.mdmsV2Util = mdmsV2Util; + this.localeUtil = localeUtil; +// this.centralInstanceUtil = centralInstanceUtil; + this.parsingUtil = parsingUtil; + this.censusUtil = censusUtil; + this.planUtil = planUtil; + this.config = config; + } + + /** + * Enriches the `PlanConfiguration` with resource mappings based on MDMS data and locale messages. + * + * @param request The request containing the configuration to enrich. + * @param localeResponse The response containing locale messages. + * @param campaignType The campaign type identifier. + * @param fileStoreId The associated file store ID. + */ + public void enrichResourceMapping(PlanConfigurationRequest request, LocaleResponse localeResponse, String campaignType, String fileStoreId) + { +// String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlanConfiguration().getTenantId()); + String rootTenantId = request.getPlanConfiguration().getTenantId().split("\\.")[0]; + String uniqueIndentifier = BOUNDARY + DOT_SEPARATOR + MICROPLAN_PREFIX + campaignType; + List mdmsV2Data = mdmsV2Util.fetchMdmsV2Data(request.getRequestInfo(), rootTenantId, MDMS_ADMIN_CONSOLE_MODULE_NAME + DOT_SEPARATOR + MDMS_SCHEMA_ADMIN_SCHEMA, uniqueIndentifier); + List columnNameList = parsingUtil.extractPropertyNamesFromAdminSchema(mdmsV2Data.get(0).getData()); + + List resourceMappingList = new ArrayList<>(); + for(String columnName : columnNameList) { + ResourceMapping resourceMapping = ResourceMapping + .builder() + .filestoreId(fileStoreId) + .mappedTo(columnName) + .active(Boolean.TRUE) + .mappedFrom(localeUtil.localeSearch(localeResponse.getMessages(), columnName)) + .build(); + UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id"); + resourceMappingList.add(resourceMapping); + } + + //enrich plan configuration with enriched resource mapping list + request.getPlanConfiguration().setResourceMapping(resourceMappingList); + + } + + public void enrichsheetWithApprovedCensusRecords(Sheet sheet, PlanConfigurationRequest planConfigurationRequest, String fileStoreId, Map mappedValues) { + List boundaryCodes = getBoundaryCodesFromTheSheet(sheet, planConfigurationRequest, fileStoreId); + + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, + parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); + + //Getting census records for the list of boundaryCodes + List censusList = getCensusRecordsForEnrichment(planConfigurationRequest, boundaryCodes); + + // Create a map from boundaryCode to Census for quick lookups + Map censusMap = censusList.stream() + .collect(Collectors.toMap(Census::getBoundaryCode, census -> census)); + + + for(Row row: sheet) { + parsingUtil.printRow(sheet, row); + // Skip the header row and empty rows + if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { + continue; + } + + // Get the boundaryCode in the current row + Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); + String boundaryCode = boundaryCodeCell.getStringCellValue(); + + Census census = censusMap.get(boundaryCode); + + if (census != null) { + // For each field in the sheetToCensusMap, update the cell if the field is editable + for (Map.Entry entry : mappedValues.entrySet()) { + String censusKey = entry.getKey(); + String sheetColumn = entry.getValue(); + + if(config.getCensusAdditionalFieldOverrideKeys().contains(censusKey)) + continue; + censusKey = config.getCensusAdditionalPrefixAppendKeys().contains(censusKey) ? CONFIRMED_KEY + censusKey : censusKey; + + // Get the column index from the mapOfColumnNameAndIndex + Integer columnIndex = mapOfColumnNameAndIndex.get(sheetColumn); + if (columnIndex != null) { + // Get the value for this field in the census, if editable + BigDecimal editableValue = getEditableValue(census, censusKey); + + if(ObjectUtils.isEmpty(editableValue)) continue; + + Cell cell = row.getCell(columnIndex); + if (cell == null) { + cell = row.createCell(columnIndex); + } + cell.setCellValue(editableValue.doubleValue()); + + } + } + } + log.info("Successfully update file with approved census data."); + } + } + + public List getBoundaryCodesFromTheSheet(Sheet sheet, PlanConfigurationRequest planConfigurationRequest, String fileStoreId) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap(ResourceMapping::getMappedTo, ResourceMapping::getMappedFrom)); + + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + + Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, + parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); + + List boundaryCodes = new ArrayList<>(); + + for (Row row : sheet) { + // Skip the header row and empty rows + if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { + continue; + } + + // Get the boundary code cell + Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); + + // Check if the cell is non-empty and collect its value + if (boundaryCodeCell != null && boundaryCodeCell.getCellType() == CellType.STRING) { + String boundaryCode = boundaryCodeCell.getStringCellValue().trim(); + if (!boundaryCode.isEmpty()) { + boundaryCodes.add(boundaryCode); + } + } + } + + return boundaryCodes; + } + + public List getCensusRecordsForEnrichment(PlanConfigurationRequest planConfigurationRequest, List boundaryCodes) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + CensusSearchCriteria censusSearchCriteria = CensusSearchCriteria.builder() + .tenantId(planConfig.getTenantId()) + .areaCodes(boundaryCodes) + .limit(boundaryCodes.size()) + .source(planConfig.getId()).build(); + + CensusSearchRequest censusSearchRequest = CensusSearchRequest.builder() + .censusSearchCriteria(censusSearchCriteria) + .requestInfo(planConfigurationRequest.getRequestInfo()).build(); + + CensusResponse censusResponse = censusUtil.fetchCensusRecords(censusSearchRequest); + + if(censusResponse.getCensus().isEmpty()) + throw new CustomException(NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_CODE, NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_MESSAGE); + + return censusResponse.getCensus(); + + } + + private BigDecimal getEditableValue(Census census, String key) { + return census.getAdditionalFields().stream() + .filter(field -> field.getEditable() && key.equals(field.getKey())) // Filter by editability and matching key + .map(field -> field.getValue()) + .findFirst() + .orElse(null); + } + + public void enrichsheetWithApprovedPlanEstimates(Sheet sheet, PlanConfigurationRequest planConfigurationRequest, String fileStoreId, Map mappedValues) { + List boundaryCodes = getBoundaryCodesFromTheSheet(sheet, planConfigurationRequest, fileStoreId); + + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, + parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); + + //Getting census records for the list of boundaryCodes + List planList = getPlanRecordsForEnrichment(planConfigurationRequest, boundaryCodes); + + // Create a map from boundaryCode to Census for quick lookups + Map planMap = planList.stream() + .collect(Collectors.toMap(Plan::getLocality, plan -> plan)); + + List outputColumnList = planList.get(0).getResources().stream() + .map(Resource::getResourceType) + .toList(); + + + for(Row row: sheet) { + // Skip the header row and empty rows + if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { + continue; + } + // Get the boundaryCode in the current row + Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); + String boundaryCode = boundaryCodeCell.getStringCellValue(); + + Plan planEstimate = planMap.get(boundaryCode); + + if (planEstimate != null) { + Map resourceTypeToEstimatedNumberMap = planEstimate.getResources().stream() + .collect(Collectors.toMap(Resource::getResourceType, Resource::getEstimatedNumber)); + + // Iterate over each output column to update the row cells with resource values + for (String resourceType : outputColumnList) { + BigDecimal estimatedValue = resourceTypeToEstimatedNumberMap.get(resourceType); + + if (estimatedValue != null) { + // Get the index of the column to update + Integer columnIndex = mapOfColumnNameAndIndex.get(resourceType); + if (columnIndex != null) { + // Update the cell with the resource value + Cell cell = row.getCell(columnIndex); + if (cell == null) { + cell = row.createCell(columnIndex); + } + cell.setCellValue(estimatedValue.doubleValue()); + } + } + } + } + log.info("Successfully update file with approved census data."); + } + } + + + public List getPlanRecordsForEnrichment(PlanConfigurationRequest planConfigurationRequest, List boundaryCodes) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + PlanSearchCriteria planSearchCriteria = PlanSearchCriteria.builder() + .tenantId(planConfig.getTenantId()) + .locality(boundaryCodes) + .limit(boundaryCodes.size()) + .planConfigurationId(planConfig.getId()).build(); + + PlanSearchRequest planSearchRequest = PlanSearchRequest.builder() + .planSearchCriteria(planSearchCriteria) + .requestInfo(planConfigurationRequest.getRequestInfo()).build(); + + PlanResponse planResponse = planUtil.search(planSearchRequest); + + if(planResponse.getPlan().isEmpty()) + throw new CustomException(NO_PLAN_FOUND_FOR_GIVEN_DETAILS_CODE, NO_PLAN_FOUND_FOR_GIVEN_DETAILS_MESSAGE); + + return planResponse.getPlan(); + } + + + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/LocaleUtil.java similarity index 89% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/LocaleUtil.java index 1ecb725308f..12fefec0405 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/LocaleUtil.java @@ -5,12 +5,9 @@ import org.egov.processor.config.Configuration; import org.egov.processor.config.ServiceConstants; import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.models.Locale; import org.egov.processor.web.models.LocaleResponse; import org.egov.processor.web.models.PlanConfigurationRequest; -import org.egov.processor.web.models.boundary.BoundarySearchResponse; -import org.egov.processor.web.models.campaignManager.Boundary; -import org.egov.processor.web.models.campaignManager.CampaignResources; -import org.egov.processor.web.models.campaignManager.CampaignResponse; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; @@ -71,10 +68,19 @@ public LocaleResponse searchLocale(PlanConfigurationRequest planConfigurationReq log.info("Locale Search successful."); return localeResponse; } catch (Exception e) { - log.error(ServiceConstants.ERROR_WHILE_SEARCHING_LOCALE + localeToUse + " and tenantId" + tenantId, e); + log.error(ServiceConstants.ERROR_WHILE_SEARCHING_LOCALE + localeToUse + " and tenantId " + tenantId, e); throw new CustomException( - ServiceConstants.ERROR_WHILE_SEARCHING_LOCALE + localeToUse + " and tenantId" + tenantId, + ServiceConstants.ERROR_WHILE_SEARCHING_LOCALE + localeToUse + " and tenantId " + tenantId, e.toString()); } } + + public String localeSearch(List localeMessages, String code) { + for (Locale locale : localeMessages) { + if (locale.getCode().equalsIgnoreCase(code)) { + return locale.getMessage(); // Return the message if code matches + } + } + return null; + } } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsUtil.java similarity index 99% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsUtil.java index 229dbf57f45..e3019ded61b 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsUtil.java @@ -132,7 +132,7 @@ public Map filterMasterData(String masterDataJson, File.InputFil String type = (String) schema.get(ServiceConstants.MDMS_SCHEMA_TYPE); String campaign = (String) schema.get(ServiceConstants.MDMS_CAMPAIGN_TYPE); // String fileT = InputFileTypeEnum.valueOf(type); - if (schema.get(ServiceConstants.MDMS_SCHEMA_SECTION).equals(ServiceConstants.FILE_TEMPLATE_IDENTIFIER) + if (schema.get(ServiceConstants.MDMS_SCHEMA_SECTION).equals(ServiceConstants.FILE_TEMPLATE_IDENTIFIER_POPULATION) && campaign.equals(campaignType) && type.equals(fileType.toString())) { Map schemaProperties = (Map) schema.get("schema"); properties = (Map) schemaProperties.get("Properties"); diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsV2Util.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsV2Util.java new file mode 100644 index 00000000000..85b87872658 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsV2Util.java @@ -0,0 +1,79 @@ +package org.egov.processor.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.processor.config.Configuration; +import org.egov.processor.web.models.mdmsV2.Mdms; +import org.egov.processor.web.models.mdmsV2.MdmsCriteriaReqV2; +import org.egov.processor.web.models.mdmsV2.MdmsCriteriaV2; +import org.egov.processor.web.models.mdmsV2.MdmsResponseV2; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; +import java.util.List; + +import static org.egov.processor.config.ServiceConstants.*; + +@Slf4j +@Component +public class MdmsV2Util { + + private RestTemplate restTemplate; + + private ObjectMapper objectMapper; + + private Configuration config; + + public MdmsV2Util(RestTemplate restTemplate, ObjectMapper objectMapper, Configuration config) + { + this.restTemplate = restTemplate; + this.objectMapper = objectMapper; + this.config = config; + } + + public List fetchMdmsV2Data(RequestInfo requestInfo, String tenantId, String schemaCode, String uniqueIdentifier) + { + StringBuilder uri = getMdmsV2Uri(); + MdmsCriteriaReqV2 mdmsCriteriaReqV2 = getMdmsV2Request(requestInfo, tenantId, schemaCode, uniqueIdentifier); + MdmsResponseV2 mdmsResponseV2 = null; + try { + mdmsResponseV2 = restTemplate.postForObject(uri.toString(), mdmsCriteriaReqV2, MdmsResponseV2.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_MDMS, e); + } + + if(ObjectUtils.isEmpty(mdmsResponseV2.getMdms())) + { + log.error(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE + " - " + tenantId); + throw new CustomException(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE, NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE); + } + + return mdmsResponseV2.getMdms(); + } + + private StringBuilder getMdmsV2Uri() + { + StringBuilder uri = new StringBuilder(); + return uri.append(config.getMdmsHost()).append(config.getMdmsV2EndPoint()); + } + + private MdmsCriteriaReqV2 getMdmsV2Request(RequestInfo requestInfo, String tenantId, String schemaCode, String uniqueIdentifier) + { + MdmsCriteriaV2 mdmsCriteriaV2 = MdmsCriteriaV2.builder() + .tenantId(tenantId) + .schemaCode(schemaCode) + .uniqueIdentifiers(Collections.singletonList(uniqueIdentifier)) + .limit(config.getDefaultLimit()) + .offset(config.getDefaultOffset()).build(); + + return MdmsCriteriaReqV2.builder() + .requestInfo(requestInfo) + .mdmsCriteriaV2(mdmsCriteriaV2).build(); + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java similarity index 59% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java index b1902b49afb..ba10327e4c8 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java @@ -1,38 +1,30 @@ package org.egov.processor.util; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.DecimalNode; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.poi.ss.usermodel.*; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.ResourceMapping; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import org.apache.commons.io.FileUtils; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.DataFormatter; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.egov.processor.web.models.PlanConfiguration; -import org.egov.processor.web.models.ResourceMapping; -import org.egov.tracer.model.CustomException; -import org.springframework.stereotype.Component; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -import lombok.extern.slf4j.Slf4j; +import static org.egov.processor.config.ServiceConstants.PROPERTIES; @Slf4j @Component @@ -63,6 +55,8 @@ public List fetchAttributeNamesFromJson(JsonNode jsonNode) } return columnNames; } + + public void validateColumnNames(List columnNamesList, PlanConfiguration planConfig, String fileStoreId ) { Set mappedFromSet = planConfig.getResourceMapping().stream() .filter(mapping -> Objects.equals(mapping.getFilestoreId(), fileStoreId)) @@ -99,12 +93,40 @@ public Map getAttributeNameIndexFromExcel(Sheet sheet) { String columnHeader = dataFormatter.formatCellValue(cell); columnIndexMap.put(columnHeader, i); } - List> sortedColumnList = new ArrayList<>(columnIndexMap.entrySet()); - Collections.sort(sortedColumnList, (o1, o2) -> (o1.getValue()).compareTo(o2.getValue())); - for (Map.Entry entry : sortedColumnList) { - sortedMap.put(entry.getKey(), entry.getValue()); + return columnIndexMap; + } + + /** + * Retrieves the mapped value from the feature JSON node using the mapped value for the given input, + * returning it as the appropriate data type. + * + * @param input The input value. + * @param feature The feature JSON node. + * @param mappedValues The mapped values. + * @return The value of the corresponding data type (Long, String, Boolean, etc.). + * @throws CustomException if the input value is not found in the feature JSON node or if the value type is unsupported. + */ + public Object extractMappedValueFromFeatureForAnInput(String input, JsonNode feature, Map mappedValues) { + // Get the value as a JsonNode, not a String + JsonNode mappedValueNode = feature.get(PROPERTIES).get(mappedValues.get(input)); + + // Check if the value exists in the JSON + if (!ObjectUtils.isEmpty(mappedValueNode)) { + + // Now return the value based on its actual type in the JsonNode + if (mappedValueNode instanceof DecimalNode) { + return ((DecimalNode) mappedValueNode).decimalValue(); // Returns BigDecimal + } else if (mappedValueNode.isBoolean()) { + return mappedValueNode.asBoolean(); + } else if (mappedValueNode.isTextual()) { + return mappedValueNode.asText(); + } else { + return null; + } + } + else { + return null; } - return sortedMap; } /** @@ -246,4 +268,128 @@ public File extractShapeFilesFromZip(PlanConfiguration planConfig, String fileSt return shpFile; } + /** + * Extracts the names of properties defined within the "numberProperties" and "stringProperties" arrays from admin schema + * + * @param rootNode The root JSON node from which to extract property names. + * @return A list of property names found in "numberProperties" and "stringProperties". + */ + public List extractPropertyNamesFromAdminSchema(JsonNode rootNode) { + List names = new ArrayList<>(); + + // Access the "properties" node directly from the root node + JsonNode propertiesNode = rootNode.path("properties"); + + // Extract names from "numberProperties" + JsonNode numberProperties = propertiesNode.path("numberProperties"); + if (numberProperties.isArray()) { + for (JsonNode property : numberProperties) { + String name = property.path("name").asText(null); + if (name != null) { + names.add(name); + } + } + } + + // Extract names from "stringProperties" + JsonNode stringProperties = propertiesNode.path("stringProperties"); + if (stringProperties.isArray()) { + for (JsonNode property : stringProperties) { + String name = property.path("name").asText(null); + if (name != null) { + names.add(name); + } + } + } + + return names; + } + + + /** + * Checks if a given row is empty. + * + * A row is considered empty if it is null or if all of its cells are empty or of type BLANK. + * + * @param row the Row to check + * @return true if the row is empty, false otherwise + */ + public static boolean isRowEmpty(Row row) { + if (row == null) { + return true; + } + for (Cell cell : row) { + if (cell != null && cell.getCellType() != CellType.BLANK) { + return false; + } + } + return true; + } + + /** + * Retrieves the index value of the boundary code from the sorted column list based on the mapped values. + * + * @param indexValue The initial index value. + * @param sortedColumnList The sorted list of column names and indices. + * @param mappedValues The map containing mapped values. + * @return The index value of the boundary code. + */ + public Integer getIndexOfBoundaryCode(Integer indexValue, List> sortedColumnList,Map mappedValues) { + for (Map.Entry entry : sortedColumnList) { + if (entry.getKey().equals(mappedValues.get(ServiceConstants.BOUNDARY_CODE))) { + indexValue = entry.getValue(); + } + } + return indexValue; + } + + /** + * Sorts the column names and indices based on the provided map of column names and indices. + * + * @param mapOfColumnNameAndIndex The map containing column names and their corresponding indices. + * @return The sorted list of column names and indices. + */ + public List> sortColumnByIndex(Map mapOfColumnNameAndIndex) { + List> sortedColumnList = new ArrayList<>(mapOfColumnNameAndIndex.entrySet()); + Collections.sort(sortedColumnList, new Comparator>() { + @Override + public int compare(Map.Entry o1, Map.Entry o2) { + return o1.getValue().compareTo(o2.getValue()); + } + }); + return sortedColumnList; + } + + public void printRow(Sheet sheet, Row row) { + System.out.print("Row -> "); + for (Cell cell : row) { + int columnIndex = cell.getColumnIndex(); + switch (cell.getCellType()) { + case STRING: + System.out.print(cell.getStringCellValue() + "\t"); + break; + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + System.out.print(cell.getDateCellValue() + "\t"); + } else { + System.out.print(cell.getNumericCellValue() + "\t"); + } + break; + case BOOLEAN: + System.out.print(cell.getBooleanCellValue() + "\t"); + break; + case FORMULA: + System.out.print(cell.getCellFormula() + "\t"); + break; + case BLANK: + System.out.print("\t"); + break; + default: + System.out.print("\t"); + break; + } + } + System.out.println(); // Move to the next line after printing the row + } + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java similarity index 85% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java index 26a11dcf976..55a8651ec56 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java @@ -1,19 +1,17 @@ package org.egov.processor.util; import com.fasterxml.jackson.databind.ObjectMapper; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import lombok.extern.slf4j.Slf4j; - import org.egov.processor.config.Configuration; import org.egov.processor.repository.ServiceRequestRepository; -import org.egov.processor.web.models.PlanConfiguration; -import org.egov.processor.web.models.PlanConfigurationResponse; -import org.egov.processor.web.models.PlanConfigurationSearchRequest; +import org.egov.processor.web.models.*; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + import static org.egov.processor.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE; @Component @@ -54,4 +52,8 @@ public List search(PlanConfigurationSearchRequest planConfigu else return planConfigurationList; } + + public void orderPlanConfigurationOperations(PlanConfigurationRequest planConfigurationRequest) { + planConfigurationRequest.getPlanConfiguration().getOperations().sort(Comparator.comparingInt(Operation::getExecutionOrder)); + } } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanUtil.java similarity index 70% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/PlanUtil.java index d44aaa2a59f..97c9810e0c5 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanUtil.java @@ -1,33 +1,26 @@ package org.egov.processor.util; -import static org.egov.processor.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY; -import static org.egov.processor.config.ServiceConstants.PROPERTIES; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.Workflow; import org.egov.processor.config.Configuration; import org.egov.processor.config.ServiceConstants; -import org.egov.processor.repository.ServiceRequestRepository; import org.egov.processor.kafka.Producer; -import org.egov.processor.web.models.Activity; -import org.egov.processor.web.models.Plan; -import org.egov.processor.web.models.PlanConfiguration; -import org.egov.processor.web.models.PlanConfigurationRequest; -import org.egov.processor.web.models.PlanConfigurationResponse; -import org.egov.processor.web.models.PlanRequest; -import org.egov.processor.web.models.Resource; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.PlanResponse; +import org.egov.processor.web.PlanSearchRequest; +import org.egov.processor.web.models.*; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Map; +import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; +import static org.egov.processor.config.ServiceConstants.*; @Component @Slf4j @@ -38,11 +31,14 @@ public class PlanUtil { private Producer producer; - public PlanUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, Producer producer) { + private ObjectMapper mapper; + + public PlanUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, Producer producer, ObjectMapper mapper) { this.serviceRequestRepository = serviceRequestRepository; this.config = config; this.producer = producer; - } + this.mapper = mapper; + } /** * Creates a plan configuration request, builds a plan request from it, and pushes it to the messaging system for further processing. @@ -55,7 +51,7 @@ public PlanUtil(ServiceRequestRepository serviceRequestRepository, Configuration public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map resultMap, Map mappedValues) { PlanRequest planRequest = buildPlanRequest(planConfigurationRequest, feature, resultMap, mappedValues); - try { + try { producer.push(config.getResourceMicroplanCreateTopic(), planRequest); } catch (Exception e) { log.error(ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY + planRequest.getPlan().getLocality(), e); @@ -80,7 +76,8 @@ private PlanRequest buildPlanRequest(PlanConfigurationRequest planConfigurationR .requestInfo(planConfigurationRequest.getRequestInfo()) .plan(Plan.builder() .tenantId(planConfig.getTenantId()) - .executionPlanId(planConfig.getExecutionPlanId()) + .planConfigurationId(planConfig.getId()) + .campaignId(planConfig.getCampaignId()) .locality(getBoundaryCodeValue(ServiceConstants.BOUNDARY_CODE, feature, mappedValues)) .resources(resultMap.entrySet().stream().map(result -> { @@ -91,6 +88,8 @@ private PlanRequest buildPlanRequest(PlanConfigurationRequest planConfigurationR }).collect(Collectors.toList())) .activities(new ArrayList()) .targets(new ArrayList()) + .workflow(Workflow.builder().action(WORKFLOW_ACTION_INITIATE).build()) + .isRequestFromResourceEstimationConsumer(true) .build()) .build(); @@ -124,9 +123,42 @@ public void update(PlanConfigurationRequest planConfigurationRequest) { try { producer.push(config.getResourceUpdatePlanConfigConsumerTopic(), planConfigurationRequest); - log.info("Plan Config updated because of Invalid data."); + log.info("Plan Config updated after processing."); } catch (Exception e) { log.error(ServiceConstants.ERROR_WHILE_UPDATING_PLAN_CONFIG); } } + + + public PlanResponse search(PlanSearchRequest planSearchRequest) { + + PlanResponse planResponse = null; + try { + Object response = serviceRequestRepository.fetchResult(getPlanSearchUri(), planSearchRequest); + planResponse = mapper.convertValue(response, PlanResponse.class); + } catch (Exception e) { + log.error(ServiceConstants.ERROR_WHILE_SEARCHING_PLAN); + } + + if (CollectionUtils.isEmpty(planResponse.getPlan())) { + throw new CustomException(NO_PLAN_FOUND_FOR_GIVEN_DETAILS_CODE, NO_PLAN_FOUND_FOR_GIVEN_DETAILS_MESSAGE); + } + + return planResponse; + } + + private StringBuilder getPlanSearchUri() { + return new StringBuilder().append(config.getPlanConfigHost()).append(config.getPlanSearchEndPoint()); + } + + public void setFileStoreIdForPopulationTemplate(PlanConfigurationRequest planConfigurationRequest, String fileStoreId) { + planConfigurationRequest.getPlanConfiguration().getFiles().stream() + .filter(file -> FILE_TEMPLATE_IDENTIFIER_POPULATION.equals(file.getTemplateIdentifier())) + .findFirst() + .ifPresent(file -> file.setFilestoreId(fileStoreId)); + + planConfigurationRequest.getPlanConfiguration().setWorkflow(null); + } + + } diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanResponse.java new file mode 100644 index 00000000000..5f4fc7b1882 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanResponse.java @@ -0,0 +1,42 @@ +package org.egov.processor.web; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.processor.web.models.Plan; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +/** + * PlanSearchResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Plan") + @Valid + private List plan = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + @JsonProperty("StatusCount") + @Valid + private Map statusCount = null; + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchCriteria.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchCriteria.java new file mode 100644 index 00000000000..eec1a370b39 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchCriteria.java @@ -0,0 +1,57 @@ +package org.egov.processor.web; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Set; + +/** + * PlanSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanSearchCriteria { + + @JsonProperty("ids") + private Set ids = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("locality") + private List locality = null; + + @JsonProperty("campaignId") + private String campaignId = null; + + @JsonProperty("planConfigurationId") + private String planConfigurationId = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("jurisdiction") + @Valid + private List jurisdiction = null; + + @JsonProperty("offset") + private Integer offset = null; + + @JsonProperty("limit") + private Integer limit = null; + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchRequest.java new file mode 100644 index 00000000000..23e4c7eb9bc --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchRequest.java @@ -0,0 +1,30 @@ +package org.egov.processor.web; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanSearchRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanSearchCriteria") + @Valid + private PlanSearchCriteria planSearchCriteria = null; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/FileController.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/FileController.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Activity.java similarity index 99% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Activity.java index fa9e1193e90..6c093ba63a2 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Activity.java @@ -1,15 +1,17 @@ package org.egov.processor.web.models; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.List; + import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; /** * Activity diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Assumption.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Assumption.java new file mode 100644 index 00000000000..5f1d262fea7 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Assumption.java @@ -0,0 +1,58 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import java.math.BigDecimal; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Digits; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * Assumption + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Assumption { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("key") + @NotNull + @Size(min = 1, max = 256) + private String key = null; + + @JsonProperty("value") + @NotNull + @Valid + @DecimalMin(value = "0.01", inclusive = true, message = "The Assumption value must be greater than 0") + @DecimalMax(value = "9999999999.99", inclusive = true, message = "The assumption value must not exceed 10 digits in total, including up to 2 decimal places.") + @Digits(integer = 10, fraction = 2, message = "The Assumption value must have up to 10 digits and up to 2 decimal points") + private BigDecimal value = null; + + @JsonProperty("source") + @NotNull(message = "Source cannot be null. Please specify a valid source.") + private Source source = null; + + @JsonProperty("category") + @NotNull + @Size(min = 2, max = 64) + private String category = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Condition.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Condition.java index 51d3511c068..c63749d5bab 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Condition.java @@ -3,11 +3,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; /** * Condition diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/File.java similarity index 81% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/File.java index fe6b6c1abab..25a62e8ac83 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/File.java @@ -1,17 +1,20 @@ package org.egov.processor.web.models; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; -import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; +import org.apache.kafka.common.protocol.types.Field; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; + +import java.util.Arrays; /** * File @@ -30,7 +33,7 @@ public class File { @JsonProperty("filestoreId") @NotNull @Size(min = 1, max = 128) - @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Filestore Id must contain alphanumeric characters and may include some special characters") + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Filestore Id must not contain only special characters") private String filestoreId = null; @JsonProperty("inputFileType") @@ -40,7 +43,7 @@ public class File { @JsonProperty("templateIdentifier") @NotNull @Size(min = 2, max = 128) - @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must contain alphanumeric characters and may include some special characters") + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must not contain only special characters") private String templateIdentifier = null; @JsonProperty("active") @@ -71,12 +74,10 @@ public String toString() { @JsonCreator public static InputFileTypeEnum fromValue(String text) { - for (InputFileTypeEnum b : InputFileTypeEnum.values()) { - if (String.valueOf(b.value).equals(text)) { - return b; - } - } - return null; + return Arrays.stream(InputFileTypeEnum.values()) + .filter(b -> String.valueOf(b.value).equals(text)) + .findFirst() + .orElse(null); // Return null if no matching enum value is found } } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Locale.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Locale.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/LocaleResponse.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/LocaleResponse.java diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/MetricDetail.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/MetricDetail.java new file mode 100644 index 00000000000..b21b1a62560 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/MetricDetail.java @@ -0,0 +1,75 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Digits; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.Arrays; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MetricDetail { + + @JsonProperty("value") + @NotNull + @DecimalMin(value = "0.01", inclusive = true, message = "Metric value must be greater than 0") + @DecimalMax(value = "999.99", inclusive = true, message = "Metric value must be less than 1000") + @Digits(integer = 3, fraction = 2, message = "Metric value must have up to 3 digits and up to 2 decimal points") + private BigDecimal metricValue = null; + + @JsonProperty("comparator") + @NotNull + private MetricComparatorEnum metricComparator = null; + + @JsonProperty("unit") + @NotNull + @Size(min = 1, max = 128) + private String metricUnit = null; + + public enum MetricComparatorEnum { + GREATER_THAN(">"), + + LESS_THAN("<"), + + GREATER_THAN_OR_EQUAL_TO(">="), + + LESS_THAN_OR_EQUAL_TO("<="), + + EQUAL("="); + + private final String symbol; + + MetricComparatorEnum(String symbol) { + this.symbol = symbol; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(symbol); + } + + @JsonCreator + public static MetricComparatorEnum fromValue(String text) { + return Arrays.stream(MetricComparatorEnum.values()) + .filter(b -> String.valueOf(b.symbol).equals(text)) + .findFirst() + .orElse(null); // Return null if no matching enum value is found + } + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Operation.java similarity index 70% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Operation.java index 25b5b189fa0..5194da66b18 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Operation.java @@ -1,17 +1,19 @@ package org.egov.processor.web.models; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; -import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; + +import java.util.Arrays; /** * Operation @@ -46,6 +48,22 @@ public class Operation { @Size(min = 1, max = 64) private String output = null; + @JsonProperty("showOnEstimationDashboard") + @NotNull + private Boolean showOnEstimationDashboard = true; + + @JsonProperty("source") + @NotNull(message = "Source cannot be null. Please specify a valid source.") + private Source source = null; + + @JsonProperty("category") + @NotNull + @Size(min = 2, max = 64) + private String category = null; + + @JsonProperty("executionOrder") + private Integer executionOrder = null; + @JsonProperty("active") @NotNull private Boolean active = true; @@ -80,12 +98,10 @@ public String toString() { @JsonCreator public static OperatorEnum fromValue(String text) { - for (OperatorEnum b : OperatorEnum.values()) { - if (String.valueOf(b.value).equals(text)) { - return b; - } - } - return null; + return Arrays.stream(OperatorEnum.values()) + .filter(b -> String.valueOf(b.value).equals(text)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unexpected value '" + text + "'")); } } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Plan.java similarity index 63% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Plan.java index a9d4f3139b5..8b2f1803f57 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Plan.java @@ -1,17 +1,20 @@ package org.egov.processor.web.models; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; -import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; import org.springframework.validation.annotation.Validated; +import java.util.List; + /** * Plan */ @@ -34,30 +37,51 @@ public class Plan { @Size(min = 1, max = 64) private String locality = null; - @JsonProperty("executionPlanId") + @JsonProperty("campaignId") @Size(max = 64) - private String executionPlanId = null; + private String campaignId = null; @JsonProperty("planConfigurationId") @Size(max = 64) private String planConfigurationId = null; + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("assignee") + @Size(max = 64) + private String assignee = null; + @JsonProperty("additionalDetails") private Object additionalDetails = null; @JsonProperty("activities") @Valid - private List activities = null; + private List activities; @JsonProperty("resources") @Valid - private List resources = null; + private List resources; @JsonProperty("targets") @Valid - private List targets = null; + private List targets; @JsonProperty("auditDetails") private AuditDetails auditDetails = null; + @JsonIgnore + private String boundaryAncestralPath = null; + + @JsonIgnore + private boolean isRequestFromResourceEstimationConsumer; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfiguration.java similarity index 68% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfiguration.java index e02d7e49b70..218dbaecbea 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfiguration.java @@ -1,14 +1,15 @@ package org.egov.processor.web.models; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotEmpty; import java.util.ArrayList; import java.util.List; + import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Pattern; import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; @@ -36,54 +37,43 @@ public class PlanConfiguration { @JsonProperty("name") @NotNull - @Size(min = 2, max = 128) - @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must not contain only special characters") + @Size(min = 3, max = 128) private String name = null; - @JsonProperty("executionPlanId") + @JsonProperty("campaignId") @NotNull @Size(min = 2, max = 64) - @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Execution Plan Id must not contain only special characters") - private String executionPlanId = null; + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Campaign Id must not contain only special characters") + private String campaignId = null; @JsonProperty("status") - @NotNull - private StatusEnum status = null; + private String status = null; @JsonProperty("files") - @NotNull - @NotEmpty @Valid private List files = new ArrayList<>(); @JsonProperty("assumptions") - @NotNull - @NotEmpty @Valid private List assumptions = new ArrayList<>(); @JsonProperty("operations") - @NotNull - @NotEmpty @Valid private List operations = new ArrayList<>(); @JsonProperty("resourceMapping") - @NotNull - @NotEmpty @Valid private List resourceMapping = new ArrayList<>(); @JsonProperty("auditDetails") private @Valid AuditDetails auditDetails; - /** - * The status used in the Plan Configuration - */ - public enum StatusEnum { - DRAFT , - GENERATED, - INVALID_DATA - } + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanRequest.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanRequest.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Resource.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Resource.java index 5fea454bd5d..693ba12ef32 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Resource.java @@ -1,14 +1,14 @@ package org.egov.processor.web.models; import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; -import java.math.BigDecimal; +import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; /** * Resource diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/ResourceMapping.java similarity index 99% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/ResourceMapping.java index c53868d1033..ee9e1869c0c 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/ResourceMapping.java @@ -1,15 +1,16 @@ package org.egov.processor.web.models; import com.fasterxml.jackson.annotation.JsonProperty; + import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; /** * ResourceMapping diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Source.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Source.java new file mode 100644 index 00000000000..3d726b35f9f --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Source.java @@ -0,0 +1,5 @@ +package org.egov.processor.web.models; + +public enum Source { + MDMS, CUSTOM, VEHICLE; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Target.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Target.java index 8d7298939f6..6855fccb123 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Target.java @@ -3,11 +3,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; /** * Target diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java similarity index 94% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java index 352b29b693b..51c390a2af5 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java @@ -1,12 +1,6 @@ package org.egov.processor.web.models.campaignManager; -import java.util.List; - -import org.egov.common.contract.models.AuditDetails; -import org.springframework.validation.annotation.Validated; - import com.fasterxml.jackson.annotation.JsonProperty; - import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; @@ -14,6 +8,10 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.List; @Validated @Data @@ -37,7 +35,13 @@ public class Campaign { @JsonProperty("action") @Size(min = 1, max = 64) private String action; - + + @JsonProperty("isActive") + private boolean isActive; + + @JsonProperty("parentId") + private String parentId; + @JsonProperty("campaignNumber") @Valid private String campaignNumber; diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetails.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetails.java new file mode 100644 index 00000000000..4bbb44b118b --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetails.java @@ -0,0 +1,32 @@ +package org.egov.processor.web.models.campaignManager; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Validated +public class MicroplanDetails { + + @JsonProperty("tenantId") + @NotNull + private String tenantId; + + @JsonProperty("campaignId") + @NotNull + private String campaignId; + + @JsonProperty("planConfigurationId") + @NotNull + private String planConfigurationId; + + @JsonProperty("resourceFilestoreId") + private String resourceFilestoreId; +} \ No newline at end of file diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetailsRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetailsRequest.java new file mode 100644 index 00000000000..4789ef42573 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetailsRequest.java @@ -0,0 +1,26 @@ +package org.egov.processor.web.models.campaignManager; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MicroplanDetailsRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("MicroplanDetails") + @Valid + private MicroplanDetails microplanDetails = null; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Product.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Product.java diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetails.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetails.java new file mode 100644 index 00000000000..b35c0343469 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetails.java @@ -0,0 +1,48 @@ +package org.egov.processor.web.models.campaignManager; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ResourceDetails { + + @JsonProperty("type") + @NotNull + @Size(min = 1, max = 64) + private String type; + + @JsonProperty("hierarchyType") + @NotNull + @Size(min = 1, max = 64) + private String hierarchyType; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId; + + @JsonProperty("fileStoreId") + @NotNull + private String fileStoreId; + + @JsonProperty("action") + @Size(min = 1, max = 64) + private String action; + + @JsonProperty("campaignId") + private String campaignId; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetailsRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetailsRequest.java new file mode 100644 index 00000000000..265d4fcdc0e --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetailsRequest.java @@ -0,0 +1,30 @@ +package org.egov.processor.web.models.campaignManager; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * CensusRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ResourceDetailsRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("ResourceDetails") + @Valid + private ResourceDetails resourceDetails = null; + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/AdditionalField.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/AdditionalField.java new file mode 100644 index 00000000000..972ca77bb4b --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/AdditionalField.java @@ -0,0 +1,48 @@ +package org.egov.processor.web.models.census; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * AdditionalField + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AdditionalField { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("key") + @Valid + @NotNull + private String key = null; + + @JsonProperty("value") + @Valid + @NotNull + private BigDecimal value = null; + + @JsonProperty("showOnUi") + private Boolean showOnUi = Boolean.TRUE; + + @JsonProperty("editable") + private Boolean editable = Boolean.TRUE; + + @JsonProperty("order") + private Integer order = null; +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/Census.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/Census.java new file mode 100644 index 00000000000..f895f6c75f1 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/Census.java @@ -0,0 +1,138 @@ +package org.egov.processor.web.models.census; + + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.List; + + +/** + * Census + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Census { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @NotNull + private String hierarchyType = null; + + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode = null; + + @JsonProperty("assignee") + @Size(max = 64) + private String assignee = null; + + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("type") + @NotNull + private TypeEnum type = null; + + @JsonProperty("totalPopulation") + @NotNull + private BigDecimal totalPopulation = null; + + @JsonProperty("populationByDemographics") + @Valid + private List populationByDemographics = null; + + @JsonProperty("effectiveFrom") + private Long effectiveFrom = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("source") + @NotNull + private String source = null; + + @JsonIgnore + private List boundaryAncestralPath = null; + + @JsonIgnore + private boolean partnerAssignmentValidationEnabled; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("additionalFields") + @Valid + private List additionalFields = null; + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; + + /** + * Gets or Sets type + */ + public enum TypeEnum { + PEOPLE("people"), + ANIMALS("animals"), + PLANTS("plants"), + OTHER("other"); + + private String value; + + TypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static TypeEnum fromValue(String text) { + for (TypeEnum b : TypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusRequest.java new file mode 100644 index 00000000000..08a9c3bdbce --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusRequest.java @@ -0,0 +1,31 @@ +package org.egov.processor.web.models.census; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * CensusRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Census") + @Valid + private Census census = null; + + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusResponse.java new file mode 100644 index 00000000000..7e6c0b77440 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusResponse.java @@ -0,0 +1,41 @@ +package org.egov.processor.web.models.census; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +/** + * CensusResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Census") + @Valid + private List census = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + @JsonProperty("StatusCount") + @Valid + private Map statusCount = null; + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchCriteria.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchCriteria.java new file mode 100644 index 00000000000..9ed59d11d63 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchCriteria.java @@ -0,0 +1,71 @@ +package org.egov.processor.web.models.census; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * CensusSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchCriteria { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("ids") + private Set ids = null; + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + private String tenantId = null; + + @JsonProperty("areaCodes") + private List areaCodes = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("source") + private String source = null; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("jurisdiction") + private List jurisdiction = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("limit") + private Integer limit = null; + + @JsonProperty("offset") + private Integer offset = null; + + public CensusSearchCriteria addAreaCodesItem(String areaCodesItem) { + if (this.areaCodes == null) { + this.areaCodes = new ArrayList<>(); + } + this.areaCodes.add(areaCodesItem); + return this; + } + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchRequest.java new file mode 100644 index 00000000000..ef7439bc368 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchRequest.java @@ -0,0 +1,31 @@ +package org.egov.processor.web.models.census; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * CensusSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("CensusSearchCriteria") + @Valid + private CensusSearchCriteria censusSearchCriteria = null; + + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/PopulationByDemographic.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/PopulationByDemographic.java new file mode 100644 index 00000000000..52ab230781b --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/PopulationByDemographic.java @@ -0,0 +1,69 @@ +package org.egov.processor.web.models.census; + + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * PopulationByDemographic + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PopulationByDemographic { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("demographicVariable") + private DemographicVariableEnum demographicVariable = null; + + @JsonProperty("populationDistribution") + private Object populationDistribution = null; + + /** + * Gets or Sets demographicVariable + */ + public enum DemographicVariableEnum { + AGE("age"), + + GENDER("gender"), + + ETHNICITY("ethnicity"); + + private String value; + + DemographicVariableEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DemographicVariableEnum fromValue(String text) { + for (DemographicVariableEnum b : DemographicVariableEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/Mdms.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/Mdms.java new file mode 100644 index 00000000000..b591caf0929 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/Mdms.java @@ -0,0 +1,55 @@ +package org.egov.processor.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * Mdms + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Mdms { + + @JsonProperty("id") + @Size(min = 2, max = 64) + private String id; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 128) + private String tenantId = null; + + @JsonProperty("schemaCode") + @NotNull + @Size(min = 2, max = 128) + private String schemaCode = null; + + @JsonProperty("uniqueIdentifier") + @Size(min = 2, max = 128) + private String uniqueIdentifier = null; + + @JsonProperty("data") + @NotNull + private JsonNode data = null; + + @JsonProperty("isActive") + private Boolean isActive = true; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + +} \ No newline at end of file diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaReqV2.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaReqV2.java new file mode 100644 index 00000000000..65c7123d5ca --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaReqV2.java @@ -0,0 +1,26 @@ +package org.egov.processor.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class MdmsCriteriaReqV2 { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo; + + @JsonProperty("MdmsCriteria") + @Valid + private MdmsCriteriaV2 mdmsCriteriaV2; +} \ No newline at end of file diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaV2.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaV2.java new file mode 100644 index 00000000000..c7832894ebc --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaV2.java @@ -0,0 +1,62 @@ +package org.egov.processor.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Data +@Validated +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class MdmsCriteriaV2 { + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + @NotNull + private String tenantId; + + @JsonProperty("ids") + private Set ids; + + @JsonProperty("uniqueIdentifier") + @Size(min = 1, max = 64) + private String uniqueIdentifier; + + @JsonProperty("uniqueIdentifiers") + private List uniqueIdentifiers; + + @JsonProperty("schemaCode") + private String schemaCode; + + @JsonProperty("filters") + private Map filterMap; + + @JsonProperty("isActive") + private Boolean isActive; + + @JsonIgnore + private Map schemaCodeFilterMap; + + @JsonIgnore + private Set uniqueIdentifiersForRefVerification; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} \ No newline at end of file diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsResponseV2.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsResponseV2.java new file mode 100644 index 00000000000..2b570e66f08 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsResponseV2.java @@ -0,0 +1,28 @@ +package org.egov.processor.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +import javax.validation.Valid; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) + +public class MdmsResponseV2 { + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("mdms") + @Valid + private List mdms = null; +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/resources/application.properties b/health-services/resource-generator/src/main/resources/application.properties similarity index 68% rename from health-services/resource-estimation-service/src/main/resources/application.properties rename to health-services/resource-generator/src/main/resources/application.properties index 7cdfe225f6d..45e36a74e5c 100644 --- a/health-services/resource-estimation-service/src/main/resources/application.properties +++ b/health-services/resource-generator/src/main/resources/application.properties @@ -1,5 +1,5 @@ -server.contextPath=/resource-estimation-service -server.servlet.context-path=/resource-estimation-service +server.contextPath=/resource-generator +server.servlet.context-path=/resource-generator server.port=8083 app.timezone=UTC @@ -47,6 +47,7 @@ kafka.producer.config.buffer_memory_config=33554432 #mdms urls egov.mdms.host=https://unified-dev.digit.org egov.mdms.search.endpoint=/egov-mdms-service/v1/_search +egov.mdms.search.v2.endpoint=/mdms-v2/v2/_search #plan config egov.plan.config.host=https://unified-dev.digit.org @@ -65,19 +66,43 @@ plan.config.consumer.kafka.update.topic=plan-config-update-topic #Plan Create egov.plan.create.endpoint=/plan-service/plan/_create +egov.plan.search.endpoint=/plan-service/plan/_search #Campaign Manager egov.project.factory.search.endpoint=/project-factory/v1/project-type/search egov.project.factory.update.endpoint=/project-factory/v1/project-type/update +egov.project.factory.data.create.endpoint=/project-factory/v1/data/_create +egov.project.factory.fetch.from.microplan.endpoint=/project-factory/v1/project-type/fetch-from-microplan egov.project.factory.host=https://unified-dev.digit.org #egov.project.factory.host=http://localhost:8090 +integrate.with.admin.console=false + +#Kafka topics for creating or updating records in dependent microservices resource.microplan.create.topic=resource-microplan-create-topic resource.update.plan.config.consumer.topic=resource-plan-config-update-topic -integrate.with.admin.console=true +resource.census.create.topic=resource-census-create-topic egov.boundary.service.host=https://unified-dev.digit.org #egov.boundary.service.host=http://localhost:8091 egov.boundary.relationship.search.endpoint=/boundary-service/boundary-relationships/_search?includeChildren=true&tenantId={tenantId}&hierarchyType={hierarchyType} egov.locale.service.host=https://unified-qa.digit.org -egov.locale.search.endpoint=/localization/messages/v1/_search?module={module}&locale={locale}&tenantId={tenantId} \ No newline at end of file +egov.locale.search.endpoint=/localization/messages/v1/_search?module={module}&locale={locale}&tenantId={tenantId} + +#trigger statuses +plan.config.trigger.plan.estimates.status=RESOURCE_ESTIMATION_IN_PROGRESS +plan.config.trigger.census.records.status=EXECUTION_TO_BE_DONE +plan.config.trigger.plan.facility.mappings.status=EXECUTION_TO_BE_DONE +plan.config.update.plan.estimates.into.output.file.status=RESOURCE_ESTIMATIONS_APPROVED + +# Pagination config +resource.default.offset=0 +resource.default.limit=10 + +# Census +egov.census.host=https://unified-dev.digit.org +egov.census.search.endpoint=/census-service/_search + +census.additional.field.override.keys=HCM_ADMIN_CONSOLE_BOUNDARY_CODE +census.additional.field.prefix.append.keys=HCM_ADMIN_CONSOLE_TOTAL_POPULATION,HCM_ADMIN_CONSOLE_TARGET_POPULATION,HCM_ADMIN_CONSOLE_TARGET_POPULATION_AGE_3TO11,HCM_ADMIN_CONSOLE_TARGET_POPULATION_AGE_12TO59 +census.additional.field.show.on.ui.false.keys=HCM_ADMIN_CONSOLE_TARGET_LAT_OPT,HCM_ADMIN_CONSOLE_TARGET_LONG_OPT \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/resources/db/Dockerfile b/health-services/resource-generator/src/main/resources/db/Dockerfile similarity index 83% rename from health-services/resource-estimation-service/src/main/resources/db/Dockerfile rename to health-services/resource-generator/src/main/resources/db/Dockerfile index 60fc07ce69f..f5241a8f861 100644 --- a/health-services/resource-estimation-service/src/main/resources/db/Dockerfile +++ b/health-services/resource-generator/src/main/resources/db/Dockerfile @@ -1,4 +1,4 @@ -FROM egovio/flyway:4.1.2 +FROM egovio/flyway:10.7.1 COPY ./migration/main /flyway/sql diff --git a/health-services/resource-generator/src/main/resources/db/migrate.sh b/health-services/resource-generator/src/main/resources/db/migrate.sh new file mode 100644 index 00000000000..c58d6f91e3f --- /dev/null +++ b/health-services/resource-generator/src/main/resources/db/migrate.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true migrate \ No newline at end of file From 8072220bb1b35047df40ff4919015832b7d51bf8 Mon Sep 17 00:00:00 2001 From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:53:20 +0530 Subject: [PATCH 15/29] Admin Console & microplanning Patch fixes on project factory (#1276) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Enabled commands for debug remotely for project factory pod (#1249) * HLM service request, updated DataTypeEnum (#872) * Service request changelog 1.5 (#875) * Added changelog and upgraded the versions for household, individual and service request * Update core-services/service-request/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/individual/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * HLM fixed merge issues * HLM fixed merge issues * HCMPRE-413: updated the changelog as per code review comments * Update health-services/project/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * HCMPRE-424: fixed hrms call from pgr-service * HCMPRE-424: updated as per code review comments * Create branch-name-validator (#960) * Create branch-name-validator * Update branch-name-validator * Update .github/workflows/branch-name-validator Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/branch-name-validator Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update branch-name-validator * Rename branch-name-validator to branch-name-validator.yml * Added census-service in build-config (#990) * [HCMPRE-658] Refractor resource-estimation-service to resource-generator (#910) Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> * Update package.json * Update tsconfig.json * Added configs and env dependencies * dockerfile update * Update tsconfig.json * Update tsconfig.json * refactored * HCM Admin Console v0.3 Release code changes (#1082) * kafka fix for large messages * Update genericUtils.ts * Update campaignValidators.ts * Fixed the mdms search path keys * fix of migration script * fix on repeated key * Update campaignApis.ts * Update campaignApis.ts * Update campaignUtils.ts * Update campaignUtils.ts * Update campaignUtils.ts * Fix project target mapping * refactored migration files fro project-factory (#867) * refactored migration files fro project-factory * updated logic for unique username generation * updated format and id name for user name * removed hash logic for username generation * added indexing on columns * updated idgen seq format for user name in index.ts * Update health-services/project-factory/src/server/api/campaignApis.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * updated logic for regenerate if campaign type differs (#876) * id generation throw error update * Enhance generate template for user and facility in update ongoing campaign flow (#885) * commit for update-generate-template * updated campaign flow generate template enhancement * just if else changes * some reformatting * update index.ts * added additional valiadtion for parent campaign * updated logic for validating parent campaign * refcatored as per change requests * update index.ts * updated logic for same campaignnumber when paren is present * updated the campaign name logic along with handling isfailed status too (#888) * updating campaign name same as parent name and number too * updated target template for updating ongoing campaign (#893) * Microplan bulk user creation (#890) * Feat : initialised bulk user creation for microplan * Enhanced user bulk upload for microplan * Fixed configs * Merge fix with console * Feat : added columns in user sheet * Added userroles sheet for bulk user template in microplan * Added source microplan while resource creation * changed logic for isSourceMicroplan * Update campaignApis.ts * Update campaignValidators.ts * changes for campaign update flow * Update campaignUtils.ts * Integrated required error messages * added numeric check in microplan phone number * Implemented no data validation * added logic for creating projects , project facility and project staff on newly added boundaries (#917) * updated target template for updating ongoing campaign * update flow campaign mapping * updated flow campaign mapping * added logic for project, project facility and project staff creation on newly added boundaries * removed one useless func * removed await from a func * removed console.logs * added some minor enhancemnets * added one edge case scenario * changed request limit to 1 mb * Feat : added locksheet filter for user microplan creation * updated logic for regenerate if campaign type differs (#876) * Enhancement for microplan user creation (#940) * some modifications for edge cases (#930) * added commit for testing update campaign flow * some chenages related to type boundary in data create api * /* MODIFIED FOR LTS UPGRADE */ * Microplan user enhancement * Some changes regarding microplan user and boundary * added some null checks * /* Temporay fix for project creation of LLIN since the structure of delivery rules is getting changed */ * Revert "/* MODIFIED FOR LTS UPGRADE */" This reverts commit 52ed7725a515fb3699f76161938add08b48202c0. * added code to add lat long in the project-factory apis * Changed code based on comments * removed default campaignid * added code to add lat long in the project-factory apis (#951) * added code to add lat long in the project-factory apis * Changed code based on comments * removed default campaignid * Fixed code to manage create * fixed the build * added for field protection on sheet data * Facility microplan validation (#975) * Microplan facility validation * Enhancement in microplan validations * Microplan sheet lock * Enhanced for multiple sheetErrors in additionalDetails * Update campaignApis.ts * fixes for filestore and unfreezing boundary code mandatory columns (#984) * Update CODEOWNERS * Update campaignValidators.ts (#987) * some correction of error after changes from microplan code merge (#988) * some correction of error after changes from microplan code merge * added question mark * added localization fix (#993) Co-authored-by: ansh-egov * Update campaignApis.ts (#994) * Added some fixes for the project transformation * Update projectTypeUtils.ts * Update campaignUtils.ts * Removed date Update projectTypeUtils.ts #1006 * HCEMPRE-809-Boundary-geometry-codes (#1011) * added localization fix * added logic for boundaryGeometryManagement * fixed some things * fixed campaign search * update project facility and staff mappings of exisitng facilities and users (#998) * some correction of error after changes from microplan code merge * added logic for updating mapping of existing facilitie and users * resolved comments by jagan on the pr for delinking and linking project resources * fetchProjectsWithBoundaryCodeAndName fucntion update * Update campaignValidators.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * added code to add lat long in the project-factory apis (#1019) * Project staff mapping correction from uuid to userserviceuuid (#1022) * some correction of error after changes from microplan code merge * corrected for mapping of project staff * added changes for project-resource mapping (#1028) * added changes for project-resource mapping * changed the variable name to boundaryProjectMappingForProjectResourceCreation from newBoundaryProjectMapping * renamed the entity --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Added logic to retry in project campaign create (#1031) * not needed to update every resource in update flow (#1036) * not needed to update every resource in update flow * added changes for if boundaries present in update flow all resources are mandate * Some checks enhancement (#1042) * Update genericApis.ts (#1043) * Update campaignValidators.ts (#1046) * consolidate resources array in update campaign flow (#1051) * consolidate resources array in update campaign flow * spelling correct * Search criteria object corrected (#1052) * consolidate resources array in update campaign flow * data search criteria id has to be an array of strings * spelling * some more corrections regarding search criteria body * Boundaries consolidate after creating child campaign (#1056) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * Boundaries correction (#1058) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * changes in extracing boundaries from campaign object * Missing resources in chid campaign to be added from parent camaig logic refactored (#1059) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * refactored logic for adding missing resources from parent campaign * Correction datatocreate column from status to userservice uuids (#1061) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * changed data to create column from user sheet * Hide Boundary and Target Old Columns (#1062) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * hide boundary code old and target old * Corrected target update flow (#1065) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * corrected target mapping in update flow * Total count of Campaigns if only is active true (#1066) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * count will be only of active campaigns * HCMPRE-1212:: migrated to point only to MMDS v2 api * Update index.ts * User/facility inactive (#1070) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * added logic for making exiting user facility inactive --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Refactor facility mappings (#1072) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * refactored facility mappings * Created enity for boundary * updated the boundary relationship function * Update index.ts * fixed some localization issue (#1075) * fixed some localization issue * fixed * Target update while campaign update flow (#1078) * consolidate resources array in update campaign flow * boundaries consolidate after creating child campaign * logic for updating targets * some refactor for adding logs and index.ts * updated the boundary localisation name --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * fixed some localization issue (#1079) * fixed some localization issue * fixed * fixed a issue * reverted failed campaign is active true from false (#1080) * reverted failed campaign is active true from false * took constants from index * refactor * Merge branch 'project-factory-kafka-fix' into console * Changed hierarchyFectch to v2 (#1077) * Changed hierarchyFectch to v2 * Changed messages * Merge branch 'project-factory-kafka-fix' into hierarchyFetchV2 --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * calll generate when create completes for type boundary management * auto generate resource if there is no previous generated history * Fixed crashloop issue (#1084) * Fixed crashloop issue * Update dataManageService.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * changed the master from hierarchyConfig to HierarchySchema (#1086) * getting boundaries split on logic change (#1088) * fixed some localization issue (#1090) * fixed some localization issue * fixed * fixed a issue * integrated microplan with console * fixxed index * fixed crashloop (#1091) * added validation for boundary bulk upload (#1092) Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * refcatored diffferent tab separation (#1093) * added timeout (#1095) * Microplan integration :: set start date to tommorow (#1096) * set start date to tommorow * updated end date * Enhance PlanFacility object (#1099) * validation for update template in create flow (#1100) * removed await (#1103) * some correction (#1104) * logic for updating targets only when present in resources array in update flow (#1105) * updated (#1106) * updated * added fix for the redis error in logs --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * added error responder (#1107) * refactored download api (#1108) * Cache issue fix(#1109) * refactored download api * refactor --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * made disable of cache always during boundary generate (#1110) Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Redis cache key deleted (#1113) * removed await * delete cache from boundary relationship search * updated redis delete func * Revert "removed await" This reverts commit a5acb54c87747f2fa8e53444c0e0af209734b126. * Update redisUtils.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * updated redis delete func (#1114) * removed cache from boundary relation create (#1115) * corrected params of auto generate after download api (#1116) * refactored consolidate (#1119) * fix on the fetch from microplan Update campaignUtils.ts (#1120) * Update microplanUtils.ts (#1123) * addded localization function (#1125) * Update SearchCriteria.ts * made createandtransfrom localization as await to upsert all localization in boundary management create flow (#1127) * added logs in handledropdownthings (#1128) * Fixed district missing issue (#1129) * Facility Village List For microplan and dropdown fix (#1130) * Facility Village List For microplan and dropdown fix * Optional chaining * Reverted recievedDropdown Changes * removed localization caceh in boundary generate flow for hierarchy module (#1133) * planFacility create Fix (#1132) * fixed the localisation cache on multiple data creates in boundary * Revert "fixed the localisation cache on multiple data creates in boundary" This reverts commit 94eb970448b4264888e589074c6292a5066222d3. * Facility fix generation for microplan (#1134) * planFacility create Fix * Fixed Facility Generation for microplan * added the count info of the localisation upsert (#1144) Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Microplan integrated with console for facility , user & target (#1151) * set start date to tommorow * updated end date * added code for target sheet * fixed * added mdms call * microplan integration changes added for target ,facility & user * undo changes * Update microplanIntergration.ts * saving all the progress on the integration * project facility mapping done * Update microplanIntergration.ts * Update microplanIntergration.ts * Update microplanIntergration.ts * target & facility integration completed statically * completed facility & target file created based on microplan * added static for user * Added user related changes * added the user integartion * added target and facility in resources array of campaign from microplan * added user in resources array in campaign object * Update microplanIntergration.ts * revert the others * Update index.ts * Cleaned up code --------- Co-authored-by: ansh-egov Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: nitish-egov * added missing default tenantid (#1152) * Boundary locale fix (#1153) * planFacility create Fix * Fixed boundary validation for different locales --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * removed duplicate key (#1154) * Logs for reordering added (#1161) * added missing default tenantid * added logs for reordering before project creation * Update index.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Readme for microplans (#1160) * Readme for microplans * Fixed boolean type * Optimized isMicroplanRequest * Optimizing roles for microplan (#1164) * Improved some performance with huge campaign object (#1165) * Trying optimised code by chatgpt * added 4mb limit * Update app.ts * Updted the comments * Changes for pollutils and reorder * Update pollUtils.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: ashish-egov * Added fixes for error during processing (#1172) * added missing default tenantid * added try catch * Update index.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * fixed the hard codings in the code (#1170) * fixed the hard codings in the code * fixed * Added filter check for the fetch from microplan if it has already some resources * fixed hardcoding in target flow (#1175) * fixed hardcoding in target flow * fixed * fixed * Update campaignApis.ts (#1177) * Update campaignApis.ts * Update campaignApis.ts * Update campaignApis.ts * Update genericUtils.ts (#1178) * changed the campaig key to activity (#1180) * added missing default tenantid * Update campaignUtils.ts * Update index.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * handled failed generations in downlaod api (#1185) * Change for roles name change (#1187) * added search before update in fetch all datas (#1190) * added seacrh before update in fetch all datas * Change for roles name change (#1187) --------- Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * formatted and made promise all to do a promise all to make calls parallely * filtered the plan facility response to have only facility which has only service boundarires * added hierarchy filteration from mdms (#1188) * added hierarchy filteration from mdms * did some hardcoding * fixed fetching of headers * added some logs * added extra loggers for fetch from microplan activities (#1193) * added extra loggers for fetch from microplan activities * Update microplanIntergration.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * added retry in localization upsert (#1194) * Adding the additonal loggers to know more informs on microplan integration * Update health-services/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fixed integration (#1197) * Global handler (#1199) * Change for roles name change * Global exception handler integrated * String logger * Update app.ts * added heap memory log & created a env variable for incomingRequestPay… …loadLimit (#1201) * added heap memory log & created a env variable for incomingRequestPayloadLimit * Update index.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Set memory limit and added log off avaiable, max limits (#1202) * added logs to check current value * Update app.ts * Update Dockerfile * Update Dockerfile * Update app.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Handle for google sheet formulas (#1207) * Update microplanValidators.ts (#1213) * Update microplanValidators.ts * Update microplanValidators.ts * Update microplanValidators.ts * Localised roles (#1217) * added change log for admin console version 0.3 (#1224) * Pvar validation (#1225) * product variant validation added * Optimized validations * Refactored * Logger error fix * Refactor * Refactor * refactored project reosurce mapping logic (#1204) * refactored project reosurce mapping logic * added new function ot search project after campaign creation time * added reference id params in project search * added logic for adding resources only for newly created projects * refactored and code clean up for project resource mapppings in update and create flow * refactor getProjectMappingBody func * some condition check * correction * removed project departments * microplan save topic changes (#1231) * Update microplanUtils.ts * Update index.ts * Update campaignApis.ts (#1232) * Update campaignApis.ts * Update campaignApis.ts * Update campaignApis.ts * Update campaignValidators.ts * Revert boundaryProject Mapping * Cleaned up data configs (#1234) * Update index.ts * Update campaignUtils.ts * Update health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update app.ts * Update health-services/project-factory/src/server/utils/microplanUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * added changes for performance testing (#1236) * added changes for performance testing * microplan save topic changes (#1231) * Update microplanUtils.ts * Update index.ts * Update campaignApis.ts (#1232) * Update campaignApis.ts * Update campaignApis.ts * Update campaignApis.ts * Update campaignValidators.ts * Revert boundaryProject Mapping * Cleaned up data configs (#1234) * Update index.ts * Update campaignUtils.ts * try catch handling * Update health-services/project-factory/src/server/service/dataManageService.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: ansh-egov <137172017+ansh-egov@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update app.ts * Update health-services/project-factory/src/server/utils/microplanUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update campaignValidators.ts (#1244) * Update campaignValidators.ts * Update campaignValidators.ts * add * added new config values * Other configs (#1250) * add * added new config values * Update request.ts --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Updating debug function for error handeling (#1243) * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/project-factory/src/server/service/dataManageService.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update dataManageService.ts * Applied code rabbit changes * refactored sheet consolidate logic (#1254) * refactored sheet consolidate logic * Applied code rabbit changes --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * refactor sheet consolidate for target (#1255) * Update package.json * Update health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * removed other ui workflows * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Update publishProjectFactory.yml * consolidate sheet handle logic change (#1256) * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: ashish-egov Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: nitish-egov Co-authored-by: ansh-egov Co-authored-by: ansh-egov <137172017+ansh-egov@users.noreply.github.com> Co-authored-by: ejagankumar <31833516+ejagankumar@users.noreply.github.com> * Changed docker file * package changes * dockerfile revert * changed package json * Update package.json * reverted other folders * reverted * Update settings.json --------- Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: kanishq-egov Co-authored-by: Sathish P Co-authored-by: tanishi-egov Co-authored-by: Palak Garg <86659286+palak-egov@users.noreply.github.com> Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Co-authored-by: nitish-egov Co-authored-by: ansh-egov Co-authored-by: ansh-egov <137172017+ansh-egov@users.noreply.github.com> Co-authored-by: ejagankumar <31833516+ejagankumar@users.noreply.github.com> * changed package json for debug (#1258) * boundary code in update flow to be persisted in db (#1259) * chnaged header creation logic in generate flow (#1261) * made few changes for fetching boundaries from boundariesCombined (#1263) * some boundary bulk and microplan user changes (#1268) * some boundary bulk and microplan user changes * Some refactoring * localisation-cache-fix (#1270) * localisation-cache-fix * Refactor * Refactor * logger added * Microplan fix (#1269) * some boundary bulk and microplan user changes * Some refactoring * Fix for target * Facility fix * User Fix * Target valiodation for microplan --------- Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: kanishq-egov Co-authored-by: Sathish P Co-authored-by: tanishi-egov Co-authored-by: Palak Garg <86659286+palak-egov@users.noreply.github.com> Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Co-authored-by: nitish-egov Co-authored-by: ansh-egov Co-authored-by: ansh-egov <137172017+ansh-egov@users.noreply.github.com> Co-authored-by: ejagankumar <31833516+ejagankumar@users.noreply.github.com> --- health-services/project-factory/Dockerfile | 4 +- health-services/project-factory/package.json | 4 +- .../src/server/config/index.ts | 5 ++ .../localisation.controller.ts | 16 +++++ .../src/server/utils/campaignUtils.ts | 7 +- .../src/server/utils/genericUtils.ts | 52 +++++++------- .../src/server/utils/microplanUtils.ts | 17 +++-- .../utils/onGoingCampaignUpdateUtils.ts | 23 ++----- .../src/server/utils/request.ts | 4 ++ .../localisationMessageConstructor.ts | 9 ++- .../server/validators/campaignValidators.ts | 6 +- .../server/validators/microplanValidators.ts | 27 +++++++- .../project-factory/tsconfig.debug.json | 68 +++++++++++++++++++ health-services/project-factory/tsconfig.json | 2 +- 14 files changed, 177 insertions(+), 67 deletions(-) create mode 100644 health-services/project-factory/tsconfig.debug.json diff --git a/health-services/project-factory/Dockerfile b/health-services/project-factory/Dockerfile index 0406e6006f1..4b942010773 100644 --- a/health-services/project-factory/Dockerfile +++ b/health-services/project-factory/Dockerfile @@ -31,6 +31,4 @@ COPY . . EXPOSE 3000 CMD ["yarn", "prod"] - # Replaced by CMD ["yarn", "prod"] - - +# Replaced by CMD ["yarn", "prod"] \ No newline at end of file diff --git a/health-services/project-factory/package.json b/health-services/project-factory/package.json index b6d62472b45..5a80dcc7147 100644 --- a/health-services/project-factory/package.json +++ b/health-services/project-factory/package.json @@ -10,11 +10,11 @@ "build": "yarn run build-ts", "build-ts": "tsc", "clean": "rm -rf ./dist", - "serve": "node dist/index.js", + "serve": "if [ \"$DEBUG\" = \"true\" ]; then node --inspect=0.0.0.0:9229 dist/index.js; else node dist/index.js; fi", "start": "yarn run dev", "test": "jest", "dev": "ts-node-dev --respawn src/server/index.ts", - "prod": "yarn build && yarn serve", + "prod": "if [ \"$DEBUG\" = \"true\" ]; then cp tsconfig.debug.json tsconfig.json; fi && yarn build && yarn serve", "watch-ts": "tsc --watch" }, "repository": { diff --git a/health-services/project-factory/src/server/config/index.ts b/health-services/project-factory/src/server/config/index.ts index 874618bcb84..862ac0a9059 100644 --- a/health-services/project-factory/src/server/config/index.ts +++ b/health-services/project-factory/src/server/config/index.ts @@ -39,6 +39,8 @@ const config = { }, facility: { facilityTab: process.env.FACILITY_TAB_NAME || "HCM_ADMIN_CONSOLE_FACILITIES", + facilityCodeColumn : "HCM_ADMIN_CONSOLE_FACILITY_CODE", + facilityType : "facility" }, user: { userTab: process.env.USER_TAB_NAME || "HCM_ADMIN_CONSOLE_USER_LIST", @@ -95,6 +97,8 @@ const config = { defaultLocale: process.env.LOCALE || "en_MZ", boundaryPrefix: "hcm-boundary", localizationModule: process.env.LOCALIZATION_MODULE || "hcm-admin-schemas", + localizationWaitTimeInBoundaryCreation: parseInt(process.env.LOCALIZATION_WAIT_TIME_IN_BOUNDARY_CREATION || "30000"), + localizationChunkSizeForBoundaryCreation: parseInt(process.env.LOCALIZATION_CHUNK_SIZE_FOR_BOUNDARY_CREATION || "2000"), }, // targetColumnsForSpecificCampaigns: { // bedNetCampaignColumns: ["HCM_ADMIN_CONSOLE_TARGET"], @@ -148,6 +152,7 @@ const config = { localizationSearch: process.env.EGOV_LOCALIZATION_SEARCH || "localization/messages/v1/_search", localizationCreate: "localization/messages/v1/_upsert", projectTypeSearch: "project-factory/v1/project-type/search", + cacheBurst: process.env.CACHE_BURST || "localization/messages/cache-bust", boundaryRelationshipCreate: "boundary-service/boundary-relationships/_create", healthIndividualSearch: process.env.EGOV_HEALTH_INDIVIDUAL_SEARCH || "health-individual/v1/_search", projectFacilitySearch: process.env.EGOV_HEALTH_PROJECT_FACILITY_SEARCH || "health-project/facility/v1/_search", diff --git a/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts index e8f97f90f5d..1c41ba84614 100644 --- a/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts +++ b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts @@ -3,6 +3,7 @@ import { logger } from "../../utils/logger"; import { httpRequest } from "../../utils/request"; import config from "../../config/index"; import { convertLocalisationResponseToMap } from "../../utils/localisationUtils"; +import { defaultRequestInfo } from "../../api/coreApis"; let cachedResponse = {}; @@ -82,6 +83,20 @@ class Localisation { ); cachedResponse = { ...this.cachedResponse }; }; + + // Calls the cache burst API of localization + public cacheBurst = async ( + ) => { + logger.info(`Calling localization cache burst api`); + const RequestInfo = defaultRequestInfo; + const requestBody = { + RequestInfo + } + await httpRequest( + this.localizationHost + config.paths.cacheBurst, + requestBody) + }; + private checkCacheAndDeleteIfExists = (module: string, locale: "string") => { logger.info( @@ -132,6 +147,7 @@ class Localisation { // Log and handle any errors that occur during the process console.log(e); logger.error(String(e)); + throw new Error(e); } }; } diff --git a/health-services/project-factory/src/server/utils/campaignUtils.ts b/health-services/project-factory/src/server/utils/campaignUtils.ts index 57a257d8092..6a24266c28c 100644 --- a/health-services/project-factory/src/server/utils/campaignUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignUtils.ts @@ -958,7 +958,7 @@ async function enrichAndPersistCampaignWithError(requestBody: any, error: any) { requestBody.CampaignDetails.status = campaignStatuses?.failed; // requestBody.CampaignDetails.isActive = false; requestBody.CampaignDetails.boundaryCode = - getRootBoundaryCode(requestBody?.CampaignDetails?.boundaries) || null; + getRootBoundaryCode(requestBody?.boundariesCombined) || null; requestBody.CampaignDetails.projectType = requestBody?.CampaignDetails?.projectType || null; requestBody.CampaignDetails.hierarchyType = @@ -1035,7 +1035,7 @@ async function enrichAndPersistCampaignForCreate( request.body.CampaignDetails.status = action == "create" ? campaignStatuses.started : campaignStatuses.drafted; request.body.CampaignDetails.boundaryCode = getRootBoundaryCode( - request.body.CampaignDetails.boundaries + request.body?.boundariesCombined ); request.body.CampaignDetails.projectType = request?.body?.CampaignDetails?.projectType || null; @@ -1111,7 +1111,7 @@ async function enrichAndPersistCampaignForUpdate( ? campaignStatuses.started : campaignStatuses.drafted; const boundaryCode = !request?.body?.CampaignDetails?.projectId - ? getRootBoundaryCode(request.body.CampaignDetails.boundaries) + ? getRootBoundaryCode(request.body?.boundariesCombined) : request?.body?.CampaignDetails?.boundaryCode || ExistingCampaignDetails?.boundaryCode; request.body.CampaignDetails.boundaryCode = boundaryCode; @@ -2414,6 +2414,7 @@ async function processAfterPersist(request: any, actionInUrl: any) { localizationMap ); } + delete request.body?.boundariesCombined; } catch (error: any) { console.log(error); logger.error(error); diff --git a/health-services/project-factory/src/server/utils/genericUtils.ts b/health-services/project-factory/src/server/utils/genericUtils.ts index da91f18f0a9..2380ecbd795 100644 --- a/health-services/project-factory/src/server/utils/genericUtils.ts +++ b/health-services/project-factory/src/server/utils/genericUtils.ts @@ -374,7 +374,7 @@ async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResour const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; let fileUrlResponse: any; - if(type != 'boundaryManagement' && request?.query?.campaignId != 'default' && type != 'boundaryGeometryManagement'){ + if (type != 'boundaryManagement' && request?.query?.campaignId != 'default' && type != 'boundaryGeometryManagement') { const responseFromCampaignSearch = await getCampaignSearchResponse(request); const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; logger.info(`checks for parent campaign for type: ${type}`) @@ -407,7 +407,7 @@ async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResour await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); request.body.generatedResource = finalResponse; } - else if (type == 'boundaryManagement' || type === 'boundaryGeometryManagement'){ + else if (type == 'boundaryManagement' || type === 'boundaryGeometryManagement') { // get boundary data from boundary relationship search api logger.info("Generating Boundary Data") const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request, false); @@ -601,10 +601,10 @@ function setAndFormatHeaders(worksheet: any, mainHeader: any, headerSet: any) { async function createReadMeSheet(request: any, workbook: any, mainHeader: any, localizationMap = {}) { const isSourceMicroplan = await isMicroplanRequest(request); let readMeConfig: any; - if(isSourceMicroplan) { + if (isSourceMicroplan) { readMeConfig = await getReadMeConfigForMicroplan(request); } - else{ + else { readMeConfig = await getReadMeConfig(request); } const headerSet = new Set(); @@ -749,13 +749,13 @@ async function createFacilityAndBoundaryFile(facilitySheetData: any, boundaryShe hideUniqueIdentifierColumn(facilitySheet, createAndSearch?.["facility"]?.uniqueIdentifierColumn); changeFirstRowColumnColour(facilitySheet, 'E06666'); - let receivedDropdowns=request.body?.dropdowns; - logger.info("started adding dropdowns in facility",JSON.stringify(receivedDropdowns)) + let receivedDropdowns = request.body?.dropdowns; + logger.info("started adding dropdowns in facility", JSON.stringify(receivedDropdowns)) - if(!receivedDropdowns||Object.keys(receivedDropdowns)?.length==0){ + if (!receivedDropdowns || Object.keys(receivedDropdowns)?.length == 0) { logger.info("No dropdowns found"); - receivedDropdowns= setDropdownFromSchema(request,schema,localizationMap); - logger.info("refetched drodowns",JSON.stringify(receivedDropdowns)) + receivedDropdowns = setDropdownFromSchema(request, schema, localizationMap); + logger.info("refetched drodowns", JSON.stringify(receivedDropdowns)) } await handledropdownthings(facilitySheet, receivedDropdowns); await handleHiddenColumns(facilitySheet, request.body?.hiddenColumns); @@ -777,7 +777,7 @@ async function handledropdownthings(sheet: any, dropdowns: any) { logger.info("Dropdowns provided:", dropdowns); for (const key of Object.keys(dropdowns)) { if (dropdowns[key]) { - logger.info(`Processing dropdown key: ${key} with values: ${dropdowns[key]}`); + logger.info(`Processing dropdown key: ${key} with values: ${dropdowns[key]}`); const firstRow = sheet.getRow(1); firstRow.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { if (cell.value === key) { @@ -815,7 +815,7 @@ async function handledropdownthings(sheet: any, dropdowns: any) { async function handleHiddenColumns(sheet: any, hiddenColumns: any) { // logger.info(sheet) - logger.info("hiddenColumns",hiddenColumns); + logger.info("hiddenColumns", hiddenColumns); if (hiddenColumns) { for (const columnName of hiddenColumns) { const firstRow = sheet.getRow(1); @@ -849,13 +849,13 @@ async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: addDataToSheet(request, userSheet, userSheetData, undefined, undefined, true, false, localizationMap, fileUrl, schema); hideUniqueIdentifierColumn(userSheet, createAndSearch?.["user"]?.uniqueIdentifierColumn); - let receivedDropdowns=request.body?.dropdowns; - logger.info("started adding dropdowns in user",JSON.stringify(receivedDropdowns)) + let receivedDropdowns = request.body?.dropdowns; + logger.info("started adding dropdowns in user", JSON.stringify(receivedDropdowns)) - if(!receivedDropdowns||Object.keys(receivedDropdowns)?.length==0){ + if (!receivedDropdowns || Object.keys(receivedDropdowns)?.length == 0) { logger.info("No dropdowns found"); - receivedDropdowns= setDropdownFromSchema(request,schema,localizationMap); - logger.info("refetched drodowns",JSON.stringify(receivedDropdowns)) + receivedDropdowns = setDropdownFromSchema(request, schema, localizationMap); + logger.info("refetched drodowns", JSON.stringify(receivedDropdowns)) } await handledropdownthings(userSheet, receivedDropdowns); await handleHiddenColumns(userSheet, request.body?.hiddenColumns); @@ -870,6 +870,8 @@ async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, fileUrl?: any) { + const type = request?.query?.type || request?.body?.ResourceDetails?.type; + const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; // Get facility and boundary data logger.info("Generating facilities started"); const allFacilities = await getAllFacilities(tenantId, request.body); @@ -881,10 +883,10 @@ async function generateFacilityAndBoundarySheet(tenantId: string, request: any, if (fileUrl) { /* fetch facility from processed file and generate facility sheet data */ + schema = await callMdmsTypeSchema(request, tenantId, true, typeWithoutWith, "all"); const processedFacilitySheetData = await getSheetData(fileUrl, localizedFacilityTab, false, undefined, localizationMap); - const modifiedProcessedFacilitySheetData = modifyProcessedSheetData(request, processedFacilitySheetData, localizationMap); + const modifiedProcessedFacilitySheetData = modifyProcessedSheetData(typeWithoutWith, processedFacilitySheetData, schema, localizationMap); facilitySheetData = modifiedProcessedFacilitySheetData; - schema = await callMdmsTypeSchema(request, tenantId, true, "facility", "all"); setDropdownFromSchema(request, schema, localizationMap); } else { @@ -903,9 +905,11 @@ async function generateFacilityAndBoundarySheet(tenantId: string, request: any, async function generateUserSheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, userData?: any, fileUrl?: any) { const tenantId = request?.query?.tenantId; + const type = request?.query?.type || request?.body?.ResourceDetails?.type; + const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; let schema: any; const isUpdate = fileUrl ? true : false; - schema = await callMdmsTypeSchema(request, tenantId, isUpdate, "user"); + schema = await callMdmsTypeSchema(request, tenantId, isUpdate, typeWithoutWith); setDropdownFromSchema(request, schema, localizationMap); const headers = schema?.columns; const localizedHeaders = getLocalizedHeaders(headers, localizationMap); @@ -917,7 +921,7 @@ async function generateUserSheet(request: any, localizationMap?: { [key: string] /* fetch facility from processed file and generate facility sheet data */ const processedUserSheetData = await getSheetData(fileUrl, localizedUserTab, false, undefined, localizationMap); - const modifiedProcessedUserSheetData = modifyProcessedSheetData(request, processedUserSheetData, localizationMap); + const modifiedProcessedUserSheetData = modifyProcessedSheetData(typeWithoutWith, processedUserSheetData, schema, localizationMap); userSheetData = modifiedProcessedUserSheetData; } else { @@ -1075,7 +1079,7 @@ async function handleGenerateError(newEntryResponse: any, generatedResource: any code: error.code, description: error.description, message: error.message - } || String(error) + } } }) generatedResource = { generatedResource: newEntryResponse }; @@ -1303,12 +1307,12 @@ async function getDataSheetReady(boundaryData: any, request: any, localizationMa mappedRowData[boundaryCodeIndex] = boundaryCode; return mappedRowData; }); - if(type == "boundaryManagement"){ + if (type == "boundaryManagement") { logger.info("Processing data for boundaryManagement type") const latLongBoundaryMap = await getLatLongMapForBoundaryCodes(request, boundaryCodeList); for (let d of data) { const boundaryCode = d[d.length - 1]; // Assume last element is the boundary code - + if (latLongBoundaryMap[boundaryCode]) { const [latitude = null, longitude = null] = latLongBoundaryMap[boundaryCode]; // Destructure lat/long d.push(latitude); // Append latitude @@ -1359,7 +1363,7 @@ function modifyDataBasedOnDifferentTab(boundaryData: any, differentTabsBasedOnLe async function getLocalizedMessagesHandler(request: any, tenantId: any, module = config.localisation.localizationModule, overrideCache = false) { const localisationcontroller = Localisation.getInstance(); const locale = getLocaleFromRequest(request); - const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId,overrideCache); + const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId, overrideCache); return localizationResponse; } diff --git a/health-services/project-factory/src/server/utils/microplanUtils.ts b/health-services/project-factory/src/server/utils/microplanUtils.ts index 1bae9d2a652..a188e01d9d3 100644 --- a/health-services/project-factory/src/server/utils/microplanUtils.ts +++ b/health-services/project-factory/src/server/utils/microplanUtils.ts @@ -62,9 +62,8 @@ export async function getUserDataFromMicroplanSheet(request: any, fileStoreId: a export function getAllUserData(request: any, userMapping: any, localizationMap: any) { const emailKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_EMAIL_MICROPLAN", localizationMap); const nameKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_NAME_MICROPLAN", localizationMap); - const phoneNumberKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER_MICROPLAN", localizationMap); validateInConsistency(request, userMapping, emailKey, nameKey); - validateNationalDuplicacy(request, userMapping, phoneNumberKey); + validateNationalDuplicacy(request, userMapping, localizationMap); const dataToCreate: any = []; for (const phoneNumber of Object.keys(userMapping)) { const roles = userMapping[phoneNumber].map((user: any) => user.role).join(','); @@ -94,7 +93,7 @@ function validateInConsistency(request: any, userMapping: any, emailKey: any, na request.body.sheetErrorDetails = Array.isArray(request.body.sheetErrorDetails) ? [...request.body.sheetErrorDetails, ...overallInconsistencies] : overallInconsistencies; } -function validateNationalDuplicacy(request: any, userMapping: any, phoneNumberKey: any) { +function validateNationalDuplicacy(request: any, userMapping: any, localizationMap: any) { const duplicates: any[] = []; for (const phoneNumber in userMapping) { @@ -102,22 +101,22 @@ function validateNationalDuplicacy(request: any, userMapping: any, phoneNumberKe const users = userMapping[phoneNumber]; for (const user of users) { - if (user.role?.startsWith("Root ")) { + const userRole = user?.role; + if (userRole?.startsWith("ROOT_")) { // Trim the role - const trimmedRole = user.role.replace("Root ", "").trim().toLowerCase(); - const trimmedRoleWithCapital = trimmedRole.charAt(0).toUpperCase() + trimmedRole.slice(1); + const trimmedRole = userRole.replace("ROOT_", ""); // Check for duplicates in the roleMap if (roleMap[trimmedRole] && roleMap[trimmedRole]["!sheet#name!"] != user["!sheet#name!"]) { - const errorMessage: any = `An user with ${trimmedRoleWithCapital} role can’t be assigned to ${user.role} role`; + const errorMessage: any = `An user with ${getLocalizedName(trimmedRole, localizationMap)} role can’t be assigned to ${getLocalizedName(userRole, localizationMap)} role`; duplicates.push({ rowNumber: user["!row#number!"], sheetName: user["!sheet#name!"], status: "INVALID", errorDetails: errorMessage }); } else { roleMap[trimmedRole] = user; } } else { - const trimmedRole = user.role.toLowerCase(); - const errorMessage: any = `An user with ${"Root " + trimmedRole} role can’t be assigned to ${user.role} role`; + const trimmedRole = userRole; + const errorMessage: any = `An user with ${getLocalizedName("ROOT_" + trimmedRole, localizationMap)} role can’t be assigned to ${getLocalizedName(userRole, localizationMap)} role`; if (roleMap[trimmedRole] && roleMap[trimmedRole]["!sheet#name!"] != user["!sheet#name!"]) { duplicates.push({ rowNumber: user["!row#number!"], sheetName: user["!sheet#name!"], status: "INVALID", errorDetails: errorMessage }); } else { diff --git a/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts b/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts index 1f4894c43b7..eeb6c2c8d9d 100644 --- a/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts +++ b/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts @@ -33,9 +33,9 @@ function getCreatedResourceIds(resources: any, type: any) { const processedType = type === 'boundary' ? 'boundaryWithTarget' : (type.includes('With') ? type.split('With')[0] : type); - return resources - .filter((item: any) => item.type === processedType) - .map((item: any) => item.createResourceId); + return resources + .filter((item: any) => item.type === processedType) + .map((item: any) => item.createResourceId); } function buildSearchCriteria(request: any, createdResourceId: any, type: any) { @@ -76,23 +76,10 @@ async function fetchFileUrls(request: any, processedFileStoreIdForUSerOrFacility -function modifyProcessedSheetData(request: any, sheetData: any, localizationMap?: any) { - // const type = request?.query?.type || request?.body?.ResourceDetails?.type; - // const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; +function modifyProcessedSheetData(type: any, sheetData: any, schema: any, localizationMap?: any) { if (!sheetData || sheetData.length === 0) return []; - // Find the row with the maximum number of keys - const maxLengthRow = sheetData.reduce((maxRow: any, row: any) => { - return Object.keys(row).length > Object.keys(maxRow).length ? row : maxRow; - }, {}); - - // Extract headers from the keys of the row with the maximum number of keys - const originalHeaders = Object.keys(maxLengthRow); - const statusIndex = originalHeaders.indexOf('#status#'); - // Insert 'errordetails' after '#status#' if found - if (statusIndex !== -1) { - originalHeaders.splice(statusIndex + 1, 0, '#errorDetails#'); - } + const originalHeaders = type === config?.facility?.facilityType ? [config?.facility?.facilityCodeColumn, ...schema?.columns] : schema?.columns; let localizedHeaders = getLocalizedHeaders(originalHeaders, localizationMap); diff --git a/health-services/project-factory/src/server/utils/request.ts b/health-services/project-factory/src/server/utils/request.ts index 9cc340605ff..88ea55b52c3 100644 --- a/health-services/project-factory/src/server/utils/request.ts +++ b/health-services/project-factory/src/server/utils/request.ts @@ -125,6 +125,10 @@ const httpRequest = async ( } return sendStatusCode ? { ...response.data, statusCode: responseStatus } : response.data; } + else{ + logger.warn(`Error occurred while making request to ${getServiceName(_url)}: with error response ${JSON.stringify(response.data)}`); + return sendStatusCode ? { ...response.data, statusCode: responseStatus } : response.data; + } } catch (error: any) { const errorResponse = error?.response; logger.error( diff --git a/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts index ed8047f9fd7..64aa3cacef5 100644 --- a/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts +++ b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts @@ -4,6 +4,7 @@ import { } from "../localisationUtils"; import Localisation from "../../controllers/localisationController/localisation.controller"; import { logger } from "../logger"; +import config from "../../config"; /** * Transforms boundary map into localisation messages and creates localisation entries. @@ -16,7 +17,7 @@ export const transformAndCreateLocalisation = async ( boundaryMap: any, request: any ) => { - const CHUNK_SIZE = 200; // Adjust this size based on your API limits and performance + const CHUNK_SIZE = config.localisation.localizationChunkSizeForBoundaryCreation try { const { tenantId, hierarchyType } = request?.body?.ResourceDetails || {}; @@ -87,6 +88,12 @@ const uploadInChunks = async (messages: any, chunkSize: any, tenantId: any, requ // Upload the current chunk await localisation.createLocalisation(chunk, tenantId, request); + // wait for 3 second + const waitTime = config.localisation.localizationWaitTimeInBoundaryCreation + logger.info(`Waiting for ${waitTime / 1000} seconds after each localisation chunk`); + await new Promise((resolve) => setTimeout(resolve, waitTime)); + await localisation.cacheBurst(); + logger.info(`Successfully uploaded chunk ${Math.floor(i / chunkSize) + 1}`); success = true; // Mark as successful break; diff --git a/health-services/project-factory/src/server/validators/campaignValidators.ts b/health-services/project-factory/src/server/validators/campaignValidators.ts index cfbc1e16997..c166daddf89 100644 --- a/health-services/project-factory/src/server/validators/campaignValidators.ts +++ b/health-services/project-factory/src/server/validators/campaignValidators.ts @@ -22,7 +22,7 @@ import { getBoundaryColumnName, getBoundaryTabName } from "../utils/boundaryUtil import addAjvErrors from "ajv-errors"; import { generateTargetColumnsBasedOnDeliveryConditions, isDynamicTargetTemplateForProjectType, modifyDeliveryConditions } from "../utils/targetUtils"; import { getBoundariesFromCampaignSearchResponse, validateBoundariesIfParentPresent } from "../utils/onGoingCampaignUpdateUtils"; -import { validateFacilityBoundaryForLowestLevel, validateLatLongForMicroplanCampaigns, validatePhoneNumberSheetWise, validateTargetsForMicroplanCampaigns, validateUniqueSheetWise, validateUserForMicroplan } from "./microplanValidators"; +import { validateExtraBoundariesForMicroplan, validateFacilityBoundaryForLowestLevel, validateLatLongForMicroplanCampaigns, validatePhoneNumberSheetWise, validateTargetsForMicroplanCampaigns, validateUniqueSheetWise, validateUserForMicroplan } from "./microplanValidators"; import { produceModifiedMessages } from "../kafka/Producer"; import { planConfigSearch, planFacilitySearch } from "../utils/microplanUtils"; import { getPvarIds } from "../utils/campaignMappingUtils"; @@ -835,13 +835,10 @@ function validateDraftProjectCampaignMissingFields(CampaignDetails: any) { async function validateParent(request: any, actionInUrl: any) { if (request?.body?.CampaignDetails?.parentId) { const tenantId = request.body.CampaignDetails?.tenantId - // const searchBodyForParent: any = { - // RequestInfo: request.body.RequestInfo, const CampaignDetails = { tenantId: tenantId, ids: [request.body.CampaignDetails?.parentId] } - // const req: any = replicateRequest(request, searchBodyForParent) const parentSearchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) if (Array.isArray(parentSearchResponse?.CampaignDetails)) { if (actionInUrl == "create") { @@ -1323,6 +1320,7 @@ async function validateDownloadRequest(request: any) { async function immediateValidationForTargetSheet(request: any, dataFromSheet: any, differentTabsBasedOnLevel: any, localizationMap: any) { logger.info("validating all district tabs present started") validateAllDistrictTabsPresentOrNot(request, dataFromSheet, differentTabsBasedOnLevel, localizationMap); + await validateExtraBoundariesForMicroplan(request, dataFromSheet, localizationMap); logger.info("validation of all district tabs present completed") for (const key in dataFromSheet) { if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { diff --git a/health-services/project-factory/src/server/validators/microplanValidators.ts b/health-services/project-factory/src/server/validators/microplanValidators.ts index 7d8d7658bf3..4bc9f35ebaf 100644 --- a/health-services/project-factory/src/server/validators/microplanValidators.ts +++ b/health-services/project-factory/src/server/validators/microplanValidators.ts @@ -1,8 +1,10 @@ -import { getBoundaryTabName } from "../utils/boundaryUtils"; +import { getBoundaryColumnName, getBoundaryTabName } from "../utils/boundaryUtils"; import createAndSearch from "../config/createAndSearch"; import { getLocalizedName } from "../utils/campaignUtils"; import { resourceDataStatuses } from "../config/constants"; import config from "../config"; +import { isMicroplanRequest } from "../utils/microplanUtils"; +import { throwError } from "../utils/genericUtils"; export function validatePhoneNumberSheetWise(datas: any[], localizationMap: any, rowMapping: any) { for (const data of datas) { @@ -268,7 +270,7 @@ function enrichErrorForFcailityMicroplan(request: any, item: any, errors: any = } const facilityCapacityColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN_${projectType}`, localizationMap); if (!item?.[facilityCapacityColumn]) { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column can’t be empty, please update the data and re-upload` }) + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column can’t be empty or zero, please update the data and re-upload` }) } else if (typeof (item?.[facilityCapacityColumn]) != "number") { errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column must be a number in between 1 and 100000000` }) @@ -298,3 +300,24 @@ export function validateFacilityBoundaryForLowestLevel(request: any, boundaries: } } } + + + +export async function validateExtraBoundariesForMicroplan(request: any, dataFromSheet: any, localizationMap: any) { + if (await isMicroplanRequest(request)) { + const campaignBoundariesSet = new Set(request?.body?.campaignBoundaries?.map((boundary: any) => boundary.code)); + for (const key in dataFromSheet) { + if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { + if (Object.prototype.hasOwnProperty.call(dataFromSheet, key)) { + const dataArray = (dataFromSheet as { [key: string]: any[] })[key]; + for (const boundaryRow of dataArray) { + const boundaryCode = boundaryRow[getLocalizedName(getBoundaryColumnName(), localizationMap)]; + if (!campaignBoundariesSet.has(boundaryCode)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Some boundaries in uploaded sheet are not present in campaign boundaries. Please upload from downloaded template only.`); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/health-services/project-factory/tsconfig.debug.json b/health-services/project-factory/tsconfig.debug.json new file mode 100644 index 00000000000..3d14147fd18 --- /dev/null +++ b/health-services/project-factory/tsconfig.debug.json @@ -0,0 +1,68 @@ +{ + "compilerOptions": { + "skipLibCheck": true, + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist/", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* Enable strict null checks. */ + "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + "typeRoots": [ + "./node_modules/@types" + ], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + }, + "include": [ + "./src/**/*" + ], + "exclude": [ + "node_modules", + "**/*.test.ts" + ] +} \ No newline at end of file diff --git a/health-services/project-factory/tsconfig.json b/health-services/project-factory/tsconfig.json index 5afabc37a6b..8843b6680c1 100644 --- a/health-services/project-factory/tsconfig.json +++ b/health-services/project-factory/tsconfig.json @@ -63,4 +63,4 @@ "node_modules", "**/*.test.ts" ] -} \ No newline at end of file +} From 3f860f8a31331f62696e38558fed7378835e87dc Mon Sep 17 00:00:00 2001 From: Naveen J <83631045+naveen-egov@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:18:28 +0530 Subject: [PATCH 16/29] Dev (#1235) * Hlm 6385 irs changes (#841) * HLM-6385: added changes for IRS activity track and closed household concepts * HLM-6385: added changes for IRS activity track and closed household concepts, added db migration script, validations for closed household * HLM-6385: added changes for location tracking * HLM-6385: added changes for location points * HLM-6385: added clientReferenceId and tenantId in LocationPoint, updated Location_capture model * HLM-6385, HCMPRE-46: Updated changes as per design review * HLM-6385, HCMPRE-46: Added Location capture changes * HLM-6385, HCMPRE-46: Added UserAction changes * HLM-6385, HCMPRE-46: updated common models, replaced digit models with service-common * Revert "HLM-6385, HCMPRE-46: updated common models, replaced digit models with service-common" This reverts commit 6abdea41edc35ce8fe9efe298438c559a664136e. * HLM-6385, HCMPRE-46: updated table informations and columns for migration scripts * reverting BoundaryUtil change * reverting BoundaryUtil changes * HLM-6385, HCMPRE-46: updated validators and IRSConsumer * HLM-6385, HCMPRE-46: updated validators * HLM-6385, HCMPRE-46: updated project configuration * HLM-6385, HCMPRE-49: updated models to have isDeleted as it is required in common utils enrichment code * HLM-6385, HCMPRE-46: updated the projectid field, added notnull annotation * HLM-6385, HCMPRE-46: updated all the changes related to enrichment * HLM-6385, HCMPRE-46: made action field notnull * HLM-6385, HCMPRE-46: updated locationCapture and userAction with mandatory latitude, longitude, locationAccuracy fields * HLM-6385, HCMPRE-46: updated locationCapture and userAction with mandatory latitude, longitude, locationAccuracy fields, HCMPRE-116, HCMPRE-117 * HLM-6385, HCMPRE-46: updated locationCapture and userAction with mandatory latitude, longitude, locationAccuracy fields, HCMPRE-116, HCMPRE-117, added in services * HLM-6385, HCMPRE-46: removed outdated changes from Task.java * removed all user location models * Refactored from LocationCapture model to UserAction and packges from irs to useraction * HLM-6385 - lat/long irs name changes * HLM Downsync Incremental product changes pull from impel (#831) * HLM Downsync Incremental product changes pull from impel * HLM removed impel specific changes * renamed Project type filter code constant * HLM updated beneficiary based search * HLM updated downsync search, cycles is required only when it is smc based campaign * HCM - removed project task resource quantity validator * HLM updated downsync logic as per review comments * HCMPRE-216 : Added Administration failed status for validation when task resource is empty or when status is ADMINISTRATION_FAILED * HCMPRE-216: updated task status * HCMPRE-216: changed to ADMINISTRATION_FAILED * HLM-6385: updated with code review comments * HLM-6385: added changes as per review comments, and added correct logs wherever required. * HLM-6385: code review comments addressed. * HLM-6385: review comment added for error handling on LocationCaptureRepository * HLM-6385: another batch of coderabbitai code review comments addressed. * HLM-6385: added more logs in repository for useraction and location capture * HLM-6385: updated the code as per code review comments from @kavi-egov --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Holash Chand * Hcmpre 240 (#846) * HLM closed household status * HCMPRE-240: validate no resource task status scenario with configurable statuses * HCMPRE-240: fixed issues related to string trimming * HLM fixed rowversion referral bug, mis placement of rowversion validator * HCMPRE-240: code review changes * HCMPRE-242: updated for null resources and address check * HCMPRE-242: added for proper null check * HCMPRE-242: added checks for task resource where ever applicable * HCMPRE-242: updated taskstatus to enum from string * HCMPRE-242, HCMPRE-240: renamed task's status field to taskStatus field, as there is contradiction with EgovModel status field * HCMPRE-242: fixed dupcalite entity cache issue for existing entity validation during bulk create * HCMPRE-242: updated project test case for taskStatus field contraints changes : not null * HCMPRE-242: fix generic repository code * HCMPRE-242: added taskstatus migration script * HCMPRE-240: updated PtIsResourceEmptyValidator, for task status * HLM-242: added changes as per code review * Revert "HCMPRE-242: added taskstatus migration script", and removed status field from EgovModel, and rename TaskStatus to status This reverts commit 7caf0c43241154bdabc97bc20c876b86d984fdb6. * HCMPRE-240: FIXED all task status reference --------- Co-authored-by: sivajiganesh-dev * HLM rowmapper issue in household, referral fixed (#848) * HLM rowmapper issue in household, referral fixed * HCMPRE-255: updated the changes for household * reverted local changes commit by mistake * added logic for cascading project date updates (#834) * added logic for cascading project date updates * updated application.properties * refactored logic for using ProjectRequest pojo to send message to kafka instead of Ancestor and Descendant Projects pojo * added comments and enhanced search project logic * made public back to private * made more concise the method in project service separated create project map logic * separated concerns of update based on action whether null or updateProjectDates * updated action logic for just test purpose * updated version of health-service-models library * update logic * updated final logic for cascading update project dates based on flag in project request * reverted config * reverted config 2 * added multiple line comments * udpated error messages * HLM fixed issues in useraction existent entity validator (#850) * HLM fixed issues in useraction existent entity validator * updated after code review comments * updated version for hcm v1.5 release (#852) * updated version for hcm v1.5 release * HLM updated the code as per code review from code rabbit * HCMPRE-209: updated code review comments and code documentation * Hcmpre 309 rebase (#857) * removed digit-models from health-services-models library * removed digit-models from health-services-models library * added SMSRequest model * Updated individual models * Updating health services models version in health services common library * version bump * hcmpre-309: merged removed-digit-models and rebase to dev * HLM-309: updated common models version --------- Co-authored-by: shubhang-egov * HCMPRE-169 code review comments (#835) * HCMPRE-169 code review comments * HCMPRE-169 adding code comments * HCMPRE-169 adding code comments * HCMPRE-169 changing mdms v2 field name for uom * HCMPRE-169 code review comments * HCMPRE-169 code review comments * HCMPRE-218 adding validation for plan config name (#844) * HCMPRE-218 adding validation for name validation * HCMPRE-218 adding validation for name validation * HCMPRE-218 moving "$." into constants * HCMPRE-218 code review comments --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HCMPRE-646: added changes (#897) * Update CODEOWNERS (#924) * Hcmpre 639 shashwat changes (#919) * Removed the project facility mapping validation check as it is not required * Removed the project facilty valaidation check in ValidatorUtil.java * Removed the local receiverId in ValidatorUtil.java --------- Co-authored-by: Shashwat12-egov * Fixed multiple role search in individual service (#992) * Hcmpre 639 shashwat changes (#973) * Removed the project facility mapping validation check as it is not required * Removed the project facilty valaidation check in ValidatorUtil.java * Removed the local receiverId in ValidatorUtil.java * Validating the sender and receiver based on transactiontype * Validating the sender and receiver based on transactiontype * Corrected the validation for the failed case * Added the comments --------- Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HCMPRE-371: Added service definition update api (#996) * update service definition api added * fix values persister config * fix "values" persister config * active added in service definition persister config * resolved code review comments * added includeDeleted parameter in search * fix some issues * fix create api * Update ValidatorUtil.java (#1112) * added-search-criterias-project-service (#1169) * Service additional field (#1146) * changed additionalDetails to additionalFields * boolean data type added in attribute definition * Added the filter for isActive * changed the serviceDefinition.code size from character varying(64) to character varying(256) * Revert "changed the serviceDefinition.code size from character varying(64) to character varying(256)" This reverts commit 24c971f354d78392b731ef8b6d8f30c861f9dc94. * Revert "Added the filter for isActive" This reverts commit 09d65c444e15b6783f629fc3b483eb2f9a5ecfd9. * changed the code character size from 64 to 256 (#1147) Co-authored-by: shubhang-eGov <70943369+shubhang-eGov@users.noreply.github.com> * added validation for boolean data type in service-request --------- Co-authored-by: yashita-egov Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: shubhang-eGov <70943369+shubhang-eGov@users.noreply.github.com> * Hcmpre 469 pagination all (#891) * HCMPRE-469: added changes for facility count * HCMPRE-469: added changes for models, added totalCount fields in required model classes * HCMPRE-469: added changes for project facility, project staff, project resource, hf-referral, stock and stock reconciliation, also added helper function in common utils for findWithCount * HCMPRE-469: added changes for removing digit-models deprecated dependency, replaced with tracer library references and mdms client references * HCMPRE-469: added changes for project service, removed reference for digits model * Removed the dev from version * Removed the dev from version of common libraries * Removed the dev from version of common libraries * Removed the order by id statement while searching the facility * Removed setting of total count line from the FacilityService file * Removed setting of total count line from the FacilityService file --------- Co-authored-by: Shashwat12-egov Co-authored-by: shubhang-eGov <70943369+shubhang-eGov@users.noreply.github.com> * PR to develop branch for Microplanning v0.1 (changes in plan-service, resource-generator service) (#1176) * HCMPRE-599 updating Plan service models * HCMPRE-599 updating Plan service models * HCMPRE-599 changes * HCMPRE-599 adding census POJOs * HCMPRE-599changes for triggering pland census records on workflow status * HCMPRE-599 app.prop changes for resource generator service * Renaming resource-estimation-service to resource-generator * HCMPRE-1078 enrichment of resource mapping * HCMPRE-1122 changing processing logic * HCMPRE-1122 changing processing logic * HCMPRE-1122 updating operation related validations * HCMPRE-1122 adding method comments * enhancement in facilityCatchmentConsumer * enhancement in facilityCatchmentConsumer * removing catchement topic that was added before * added wf validation for approving estimations * adding additionalDetails as string while preparing rows for batchUpdate * adding additionalDetails as string while preparing rows for batchUpdate * HCMPRE-1094 changes for facility mapping create trigger on workflow * reverting the change in census-bulk-api * parsing additional details in bulk update api * Added plan config name in plan employee's and plan facility's search criteria * Bypassing validations for operations when source is CUSTOM * added workflow validations * removing unused service constants * Changes for triggering plan-facility mapping * adding project factory data create host * handling case for empty areaCodes in search criteria * handling case for empty areaCodes in search criteria * adding project factory data create host * Adding facility create trigger status * Adding additionalField table in census * adding plan config name in plan employee and plan facility pojo * Adding additionalField table in census * implemented partial search in plan config name * Changing datatype of value * HCMPRE-1162 enrich additionalfieldForCensus * HCMPRE-1162 enrich additionalfieldForCensus * updated query builder for census * handling null pointer exception on updating additional details * Changes to allow assumption values in input * Removing older method for getting input value * Making editable false for uploaded additional field during census create * HCMPRE-853 removing lat long fields from additional field overridekeys * Changes for adding execution order for operations * Changes for adding execution order for operations * Adding facilityName column and enriching servingPop * HCMPRE-853 added chnages for census search and fetching boundarycodes from one sheet * HCMPRE-853 changes for updating file with approved census data * HCMPRE-853 adding logs * pull from microplanning-dev * HCMPRE-853 integrating with project factory with updated resources * modification in wf-service * workflow auto-assignee issue * HCMPRE-853 commenting project factory integration * adding pagination for plan-employee api * changed the data type of BigDecimal * HCMPRE-1282 changes for updating estimates into plan * HCMPRE-1282 app.prop changes * Adding case for when celltype is formula. * enriching additional details with additional field key-value * modified orderBy clause * made changes in order by clause * added facilityType * pull from microplanning-dev * making fuzzy search cAse-insenSItive * making fuzzy search cAse-insenSItive * making fuzzy search cAse-insenSItive * pull from microplanning-dev * pull from microplanning-dev * modified pagination * HCMPRE-1282 changes for updating approved plans into file for campaign integration * added planConfigStatus in search criteria * HCMPRE-1282 changes for updating approved plans into file for campaign integration * HCMPRE-771 merging multiple alter table migration scripts into create table scripts. * Adding workflow restricted roles in census * Adding workflow restricted roles in census * Fixing limit and adding check for empty row * Fixing limit and adding check for empty row * added ranked query for plan employee assignment * added ranked query for plan employee assignment * HCMPRE-1300 DB migration script cleanup * adding plan bulk update topic * Adding facility name in census additional details * Wf auto assignment to multiple people * Wf auto assignment to multiple people * Adding boundaryTypeHierarchy Pojos and search endpoint * enriching jurisdiction mapping in census * changing jurisdictionMapping from jsonIgnore to jsonProperty * optimizing the enrichment functions and adding comments * handling null pointer exception * Wf auto assignment to multiple people * Set last modified time on update call * enriching serving population with sum of confirmed target population of serving boundaries * Reverting campaign update at the end. * modifying Wf for send back actions * enriching jurisdiction mapping in plan * setting assignees separetly for send back actions * Changing assignee column to Text in db * Changing assignee column to Text in db * enriching jurisdiction mapping * Changing validation logic for operations * enriching jurisdiction mapping * Changes for only validating when operation is active * Sort operations in planconfig search by execution order * Sort operations in planconfig search by execution order * Sort operations in planconfig search by execution order * Sort operations in planconfig search by execution order * type casting jurisdiction into list * Adding census changelog * Adding census changelog * Adding census changelog * Adding census changelog * Adding census changelog * Show on UI false for lat long fields * Updated plan service CHANGELOG * update plan config validation * Adding jurisdiction mapping in plan facility * Changing all collection dataType from list to set in API search criteria * Changing all collection dataType from list to set in API search criteria * removing validation for operation source * adding overloaded method for query builder in plan * adding overloaded method for query builder in plan * Adding validation to check for duplicates * pull from census-bulk-api * pull from census-bulk-api * Removing comments from WF in resource generator * Decreasing min size of assumptionvalue in Operation POJO to 1. * Changing mdms master in plan service for hierarchyConfig * changing min size of resource type in resource pojo * increasing request size for producer * changed version from 1.1.0 to 1.0.0 * changed version from 1.1.0 to 1.0.0 * changing the order * changing the order * changing the order * Increasing request size in application.properties * Updating resource generator changelog * Updating resource generator changelog * Adding boundaryAncestralPath for Plan Facility API * Adding boundaryAncestralPath for Plan Facility API * Adding ProjectFactory consumer in Plan Facility Service * Adding ProjectFactory consumer in Plan Facility Service * Adding plan changelog * Adding empty list as service boundary when null in consumer for project-factory * Increasing the max-request-size in census producer configuration * Increasing the max-request-size in plan producer configuration * Adding orderBy clause for plan search query * Removing unused census consumer * Replacing map from set for duplicate check in census row mapper * Replacing map from set for duplicate check in plan config row mapper * Replacing map from set for duplicate check in census row mapper * Replacing map from set for duplicate check in census row mapper * Replacing map from set for duplicate check in plan config row mapper * Replacing map from set for duplicate check in plan row mapper * Clearing set on new census entry * Clearing set on new plan entry * Clearing set on new plan config entry --------- Co-authored-by: Shashwat Mishra <71879793+shashwat-egov@users.noreply.github.com> Co-authored-by: Tanishi Goyal --------- Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Holash Chand Co-authored-by: sivajiganesh-dev Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Co-authored-by: shubhang-egov Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Co-authored-by: Shashwat12-egov Co-authored-by: Shashwat Mishra <71879793+shashwat-egov@users.noreply.github.com> Co-authored-by: yashita-egov Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: shubhang-eGov <70943369+shubhang-eGov@users.noreply.github.com> Co-authored-by: Tanishi Goyal --- CODEOWNERS | 2 +- core-services/service-request/pom.xml | 2 +- .../servicerequest/config/Configuration.java | 3 + .../egov/servicerequest/error/ErrorCode.java | 16 ++ .../ServiceDefinitionQueryBuilder.java | 8 +- .../ServiceDefinitionRequestService.java | 14 +- .../ServiceRequestEnrichmentService.java | 65 +++++++ .../ServiceDefinitionRequestValidator.java | 67 +++++-- .../validators/ServiceRequestValidator.java | 24 +-- .../web/models/AttributeDefinition.java | 6 +- .../web/models/AttributeValue.java | 2 +- .../servicerequest/web/models/Service.java | 2 +- .../web/models/ServiceDefinition.java | 4 +- .../ServiceDefinitionSearchRequest.java | 3 +- .../src/main/resources/application.properties | 1 + ...115143930__servicedefinition_alter_ddl.sql | 9 + .../resources/service-request-persister.yml | 183 +++++++++++++----- health-services/facility/pom.xml | 4 +- .../repository/FacilityRepository.java | 21 +- .../rowmapper/FacilityRowMapper.java | 2 +- .../facility/service/FacilityService.java | 21 +- .../validator/FNonExistentValidator.java | 2 +- .../validator/FRowVersionValidator.java | 2 +- .../controllers/FacilityApiController.java | 7 +- .../NonExistentEntityValidatorTest.java | 8 +- .../validator/RowVersionValidatorTest.java | 8 +- health-services/individual/pom.xml | 4 +- .../repository/IndividualRepository.java | 8 +- .../rowmapper/AddressRowMapper.java | 10 +- .../rowmapper/IdentifierRowMapper.java | 8 +- .../rowmapper/IndividualRowMapper.java | 4 +- .../repository/rowmapper/SkillRowMapper.java | 8 +- .../individual/service/EnrichmentService.java | 2 +- .../service/NotificationService.java | 12 +- .../libraries/health-services-common/pom.xml | 15 +- .../data/repository/GenericRepository.java | 48 +++++ .../helper/AuditDetailsTestBuilder.java | 2 +- .../org/egov/common/service/IdGenService.java | 8 +- .../org/egov/common/service/UserService.java | 4 +- .../org/egov/common/utils/CommonUtils.java | 2 +- .../org/egov/common/helpers/SomeObject.java | 2 +- .../helpers/SomeObjectWithClientRefId.java | 2 +- .../egov/common/utils/CommonUtilsTest.java | 2 +- .../libraries/health-services-models/pom.xml | 7 +- .../org/egov/common/models/core/Boundary.java | 5 +- .../egov/common/models/core/EgovModel.java | 7 +- .../common/models/core/EgovOfflineModel.java | 7 +- .../egov/common/models/core/SMSRequest.java | 18 ++ .../models/facility/AdditionalFields.java | 12 +- .../egov/common/models/facility/Facility.java | 9 +- .../models/facility/FacilityBulkRequest.java | 12 +- .../models/facility/FacilityBulkResponse.java | 33 +++- .../models/facility/FacilityRequest.java | 5 +- .../models/facility/FacilityResponse.java | 5 +- .../facility/FacilitySearchRequest.java | 5 +- .../common/models/facility/TenantRole.java | 10 +- .../egov/common/models/facility/UserInfo.java | 10 +- .../models/household/AdditionalFields.java | 12 +- .../egov/common/models/household/Field.java | 5 +- .../common/models/household/Household.java | 2 +- .../household/HouseholdBulkRequest.java | 12 +- .../household/HouseholdBulkResponse.java | 10 +- .../models/household/HouseholdMember.java | 8 +- .../household/HouseholdMemberBulkRequest.java | 12 +- .../HouseholdMemberBulkResponse.java | 10 +- .../household/HouseholdMemberRequest.java | 5 +- .../household/HouseholdMemberResponse.java | 5 +- .../HouseholdMemberSearchRequest.java | 5 +- .../models/household/HouseholdRequest.java | 5 +- .../models/household/HouseholdResponse.java | 5 +- .../household/HouseholdSearchRequest.java | 5 +- .../common/models/household/TenantRole.java | 10 +- .../common/models/household/UserInfo.java | 10 +- .../models/individual/AdditionalFields.java | 12 +- .../common/models/individual/Address.java | 13 +- .../egov/common/models/individual/Field.java | 5 +- .../common/models/individual/Identifier.java | 9 +- .../common/models/individual/Individual.java | 17 +- .../individual/IndividualBulkRequest.java | 12 +- .../individual/IndividualBulkResponse.java | 34 ++-- .../models/individual/IndividualRequest.java | 5 +- .../models/individual/IndividualResponse.java | 5 +- .../egov/common/models/individual/Name.java | 3 +- .../egov/common/models/individual/Skill.java | 9 +- .../common/models/individual/UserDetails.java | 10 +- .../models/product/AdditionalFields.java | 12 +- .../org/egov/common/models/product/Field.java | 5 +- .../egov/common/models/product/Product.java | 8 +- .../common/models/product/ProductRequest.java | 12 +- .../models/product/ProductResponse.java | 10 +- .../models/product/ProductSearchRequest.java | 5 +- .../common/models/product/ProductVariant.java | 5 +- .../models/product/ProductVariantRequest.java | 12 +- .../product/ProductVariantResponse.java | 10 +- .../product/ProductVariantSearchRequest.java | 5 +- .../models/product/ProjectProductVariant.java | 3 +- .../common/models/product/TenantRole.java | 10 +- .../egov/common/models/product/UserInfo.java | 10 +- .../models/project/AdditionalFields.java | 12 +- .../egov/common/models/project/Address.java | 11 +- .../project/BeneficiaryBulkRequest.java | 12 +- .../project/BeneficiaryBulkResponse.java | 10 +- .../models/project/BeneficiaryRequest.java | 5 +- .../models/project/BeneficiaryResponse.java | 5 +- .../project/BeneficiarySearchRequest.java | 5 +- .../egov/common/models/project/Document.java | 9 +- .../org/egov/common/models/project/Field.java | 5 +- .../egov/common/models/project/Project.java | 10 +- .../models/project/ProjectBeneficiary.java | 11 +- .../project/ProjectFacilityBulkRequest.java | 12 +- .../project/ProjectFacilityBulkResponse.java | 34 +++- .../project/ProjectFacilityRequest.java | 5 +- .../project/ProjectFacilityResponse.java | 5 +- .../models/project/ProjectProductVariant.java | 3 +- .../common/models/project/ProjectRequest.java | 12 +- .../models/project/ProjectResource.java | 9 +- .../project/ProjectResourceBulkRequest.java | 12 +- .../project/ProjectResourceBulkResponse.java | 15 +- .../project/ProjectResourceRequest.java | 5 +- .../project/ProjectResourceResponse.java | 5 +- .../models/project/ProjectResponse.java | 10 +- .../models/project/ProjectSearchRequest.java | 1 - .../common/models/project/ProjectStaff.java | 17 +- .../project/ProjectStaffBulkRequest.java | 12 +- .../project/ProjectStaffBulkResponse.java | 37 +++- .../models/project/ProjectStaffRequest.java | 5 +- .../models/project/ProjectStaffResponse.java | 5 +- .../common/models/project/ProjectType.java | 12 +- .../org/egov/common/models/project/Role.java | 5 +- .../egov/common/models/project/Target.java | 2 +- .../models/project/TaskBulkRequest.java | 12 +- .../models/project/TaskBulkResponse.java | 10 +- .../common/models/project/TaskRequest.java | 5 +- .../common/models/project/TaskResource.java | 2 +- .../models/project/TaskResourceRequest.java | 12 +- .../models/project/TaskResourceResponse.java | 10 +- .../common/models/project/TaskResponse.java | 5 +- .../models/project/TaskSearchRequest.java | 5 +- .../common/models/project/TenantRole.java | 10 +- .../egov/common/models/project/UserInfo.java | 10 +- .../models/project/UserServiceResponse.java | 6 +- .../models/referralmanagement/Referral.java | 1 - .../hfreferral/HFReferral.java | 1 - .../hfreferral/HFReferralBulkResponse.java | 18 ++ .../sideeffect/SideEffect.java | 1 - .../common/models/stock/AdditionalFields.java | 12 +- .../org/egov/common/models/stock/Field.java | 5 +- .../org/egov/common/models/stock/Stock.java | 8 +- .../common/models/stock/StockBulkRequest.java | 12 +- .../models/stock/StockBulkResponse.java | 36 +++- .../models/stock/StockReconciliation.java | 9 +- .../stock/StockReconciliationBulkRequest.java | 12 +- .../StockReconciliationBulkResponse.java | 35 +++- .../stock/StockReconciliationRequest.java | 5 +- .../stock/StockReconciliationResponse.java | 5 +- .../StockReconciliationSearchRequest.java | 5 +- .../common/models/stock/StockRequest.java | 5 +- .../common/models/stock/StockResponse.java | 5 +- .../models/stock/StockSearchRequest.java | 5 +- .../egov/common/models/stock/TenantRole.java | 10 +- .../egov/common/models/stock/UserInfo.java | 10 +- .../java/digit/service/PlanValidator.java | 2 +- health-services/project/pom.xml | 4 +- .../project/config/ProjectConfiguration.java | 3 + .../repository/ProjectFacilityRepository.java | 11 +- .../ProjectAddressQueryBuilder.java | 12 ++ .../rowmapper/DocumentRowMapper.java | 2 +- .../rowmapper/LocationCaptureRowMapper.java | 2 +- .../rowmapper/ProjectAddressRowMapper.java | 2 +- .../ProjectBeneficiaryRowMapper.java | 2 +- .../rowmapper/ProjectFacilityRowMapper.java | 2 +- .../rowmapper/ProjectResourceRowMapper.java | 2 +- .../rowmapper/ProjectRowMapper.java | 2 +- .../rowmapper/ProjectStaffRowMapper.java | 2 +- .../rowmapper/ProjectTaskRowMapper.java | 2 +- .../repository/rowmapper/TargetRowMapper.java | 2 +- .../rowmapper/TaskResourceRowMapper.java | 2 +- .../rowmapper/UserActionRowMapper.java | 2 +- .../service/ProjectFacilityService.java | 31 +-- .../service/ProjectResourceService.java | 18 +- .../egov/project/service/ProjectService.java | 2 +- .../project/service/ProjectStaffService.java | 20 +- .../service/enrichment/ProjectEnrichment.java | 2 +- .../ProjectTaskEnrichmentService.java | 2 +- .../org/egov/project/util/BoundaryUtil.java | 16 +- .../java/org/egov/project/util/MDMSUtils.java | 8 +- .../egov/project/util/ProjectServiceUtil.java | 2 +- .../beneficiary/BeneficiaryValidator.java | 8 +- .../validator/project/ProjectValidator.java | 2 +- .../validator/staff/PsUserIdValidator.java | 14 +- .../task/PtResourceQuantityValidator.java | 8 +- .../web/controllers/ProjectApiController.java | 10 +- .../ProjectResourceApiController.java | 8 +- .../src/main/resources/application.properties | 6 +- .../ProjectBeneficiaryServiceCreateTest.java | 2 +- .../ProjectBeneficiaryServiceUpdateTest.java | 2 +- .../ProjectFacilityServiceSearchTest.java | 14 +- .../ProjectStaffServiceSearchTest.java | 13 +- .../ProjectFacilityApiControllerTest.java | 6 +- .../ProjectStaffApiControllerTest.java | 3 +- health-services/referralmanagement/pom.xml | 4 +- .../repository/HFReferralRepository.java | 19 +- .../rowmapper/HFReferralRowMapper.java | 2 +- .../rowmapper/ReferralRowMapper.java | 2 +- .../rowmapper/SideEffectRowMapper.java | 2 +- .../service/HFReferralService.java | 16 +- .../service/MasterDataService.java | 10 +- .../util/ValidatorUtil.java | 2 +- .../HfrNonExistentEntityValidator.java | 3 +- .../hfreferral/HfrRowVersionValidator.java | 2 +- .../controllers/HFReferralApiController.java | 8 +- .../egov/processor/service/ExcelParser.java | 4 + .../egov/processor/util/EnrichmentUtil.java | 2 + health-services/stock/pom.xml | 4 +- .../StockReconciliationRowMapper.java | 2 +- .../repository/rowmapper/StockRowMapper.java | 2 +- .../egov/stock/service/FacilityService.java | 23 ++- .../service/StockReconciliationService.java | 18 +- .../org/egov/stock/service/StockService.java | 18 +- .../org/egov/stock/util/ValidatorUtil.java | 43 +++- .../web/controllers/StockApiController.java | 5 +- .../StockReconciliationApiController.java | 8 +- 222 files changed, 1312 insertions(+), 879 deletions(-) create mode 100644 core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SMSRequest.java diff --git a/CODEOWNERS b/CODEOWNERS index 30885762527..7833b872775 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,3 @@ * @kavi-egov @sathishp-eGov -health-services/project-factory/ @jagankumar-egov +health-services/project-factory/ @jagankumar-egov diff --git a/core-services/service-request/pom.xml b/core-services/service-request/pom.xml index 5b5bfe71423..f04bced991b 100644 --- a/core-services/service-request/pom.xml +++ b/core-services/service-request/pom.xml @@ -43,7 +43,7 @@ org.flywaydb flyway-core - 9.22.3 + org.postgresql diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/config/Configuration.java b/core-services/service-request/src/main/java/org/egov/servicerequest/config/Configuration.java index 2d5b8f71444..4aa6a5d519b 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/config/Configuration.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/config/Configuration.java @@ -55,6 +55,9 @@ public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectM @Value("${egov.service.definition.create.topic}") private String serviceDefinitionCreateTopic; + @Value("${egov.service.definition.update.topic}") + private String serviceDefinitionUpdateTopic; + @Value("${egov.service.create.topic}") private String serviceCreateTopic; diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java b/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java index 754e55208bb..e1a99338c3c 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java @@ -1,6 +1,7 @@ package org.egov.servicerequest.error; import org.springframework.stereotype.Component; +import org.apache.kafka.common.protocol.types.Field; @Component public class ErrorCode { @@ -30,6 +31,8 @@ public class ErrorCode { public static final String SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG = "Attribute Value provided against the attribute definition of type multi value list must be an instance of list"; + public static final String SERVICE_REQUEST_ATTRIBUTE_INVALID_BOOLEAN_VALUE_MSG = "Attribute Value provided against the attribute definition of type boolean must be an instance of boolean"; + public static final String INVALID_SIZE_OF_INPUT_CODE = "INVALID_SIZE_OF_INPUT_CODE"; public static final String INVALID_SIZE_OF_TEXT_MSG = "Text value cannot be of length greater than configured length "; @@ -61,4 +64,17 @@ public class ErrorCode { public static final String INVALID_REGEX_ERR_CODE = "INVALID_REGEX_ERR_CODE"; public static final String INVALID_REGEX_ERR_MSG = "The provided regex failed to compile for attribute definition with code - "; + + public static final String SERVICE_DEFINITION_NOT_EXIST_ERR_CODE = "SERVICE_DEFINITION_NOT_EXIST_ERR_CODE"; + + public static final String SERVICE_DEFINITION_NOT_EXIST_ERR_MSG = "Provided tenantId and code unique combination does not exist"; + + public static final String VALID_SERVICE_EXIST_ERR_CODE = "VALID_SERVICE_EXIST_ERR_CODE"; + + public static final String VALID_SERVICE_EXIST_ERR_MSG = "Valid Service exists corresponding to Service Definition"; + + public static final String INACTIVE_SERVICE_DEFINITION_ERR_CODE = "INACTIVE_SERVICE_DEFINITION_ERR_CODE"; + + public static final String INACTIVE_SERVICE_DEFINITION_ERR_MSG = "Inactive Service Definition cannot be updated"; + } diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/repository/querybuilder/ServiceDefinitionQueryBuilder.java b/core-services/service-request/src/main/java/org/egov/servicerequest/repository/querybuilder/ServiceDefinitionQueryBuilder.java index afd7c2ef680..feabdbba147 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/repository/querybuilder/ServiceDefinitionQueryBuilder.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/repository/querybuilder/ServiceDefinitionQueryBuilder.java @@ -56,9 +56,11 @@ public String getServiceDefinitionsIdsQuery(ServiceDefinitionSearchRequest servi } // Fetch service definitions which have NOT been soft deleted - addClauseIfRequired(query, preparedStmtList); - query.append(" sd.isActive = ? "); - preparedStmtList.add(Boolean.TRUE); + if(!serviceDefinitionSearchRequest.isIncludeDeleted()){ + addClauseIfRequired(query, preparedStmtList); + query.append(" sd.isActive = ? "); + preparedStmtList.add(Boolean.TRUE); + } // order service definitions based on their createdtime in latest first manner query.append(ORDERBY_CREATEDTIME); diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceDefinitionRequestService.java b/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceDefinitionRequestService.java index 185274a0eae..64c3c52b6ea 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceDefinitionRequestService.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceDefinitionRequestService.java @@ -68,7 +68,19 @@ public List searchServiceDefinition(ServiceDefinitionSearchRe public ServiceDefinition updateServiceDefinition(ServiceDefinitionRequest serviceDefinitionRequest) { - // TO DO + ServiceDefinition serviceDefinition = serviceDefinitionRequest.getServiceDefinition(); + + //Validate incoming service definition request + ServiceDefinition definitionFromDb = serviceDefinitionRequestValidator.validateUpdateRequest(serviceDefinitionRequest); + + //Enrich incoming service definition request + enrichmentService.enrichServiceDefinitionUpdateRequest(serviceDefinitionRequest, definitionFromDb); + + // Producer statement to emit service definition to kafka for persisting + producer.push(config.getServiceDefinitionUpdateTopic(), serviceDefinitionRequest); + + // Restore attribute values to the type in which it was sent in service definition request + enrichmentService.setAttributeDefinitionValuesBackToNativeState(serviceDefinition); return serviceDefinitionRequest.getServiceDefinition(); } diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceRequestEnrichmentService.java b/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceRequestEnrichmentService.java index 90b9729f864..0864c204d42 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceRequestEnrichmentService.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceRequestEnrichmentService.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; @Component public class ServiceRequestEnrichmentService { @@ -110,4 +111,68 @@ public void setAttributeValuesBackToNativeState(ServiceRequest serviceRequest, M attributeValue.setValue(attributeCodeVsValueMap.get(attributeValue.getAttributeCode())); }); } + + private void updateAttributeDefinition(AttributeDefinition attributeDefinition, AttributeDefinition existingAttributeDefinition, RequestInfo requestInfo){ + + attributeDefinition.setId(existingAttributeDefinition.getId()); + + attributeDefinition.setAuditDetails(existingAttributeDefinition.getAuditDetails()); + + attributeDefinition.setReferenceId(existingAttributeDefinition.getReferenceId()); + + attributeDefinition.getAuditDetails().setLastModifiedTime(System.currentTimeMillis()); + + attributeDefinition.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUuid()); + + } + private void upsertAttributeDefinition(AttributeDefinition attributeDefinition, ServiceDefinitionRequest serviceDefinitionRequest){ + RequestInfo requestInfo = serviceDefinitionRequest.getRequestInfo(); + + attributeDefinition.setId(UUID.randomUUID().toString()); + + attributeDefinition.setAuditDetails( + AuditDetails.builder() + .createdBy(requestInfo.getUserInfo().getUuid()) + .createdTime(System.currentTimeMillis()) + .lastModifiedBy(requestInfo.getUserInfo().getUuid()) + .lastModifiedTime(System.currentTimeMillis()) + .build() + ); + + attributeDefinition.setReferenceId(serviceDefinitionRequest.getServiceDefinition().getId()); + } + public void enrichServiceDefinitionUpdateRequest(ServiceDefinitionRequest serviceDefinitionRequest, ServiceDefinition definitionFromDb) { + List attributeDefinitions = serviceDefinitionRequest.getServiceDefinition().getAttributes(); + + //For quick lookup of Attribute Definition with Code + Map existingAttributeCode = definitionFromDb + .getAttributes() + .stream() + .collect(Collectors.toMap(AttributeDefinition::getCode, a->a)); + + RequestInfo requestInfo = serviceDefinitionRequest.getRequestInfo(); + + ServiceDefinition serviceDefinition = serviceDefinitionRequest.getServiceDefinition(); + + serviceDefinition.setId(definitionFromDb.getId()); + serviceDefinition.setAuditDetails(definitionFromDb.getAuditDetails()); + serviceDefinition.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUuid()); + serviceDefinition.getAuditDetails().setLastModifiedTime(System.currentTimeMillis()); + + attributeDefinitions.forEach(attributeDefinition -> { + if(existingAttributeCode.containsKey(attributeDefinition.getCode())){ + updateAttributeDefinition(attributeDefinition, existingAttributeCode.get(attributeDefinition.getCode()), requestInfo); + } + else{ + upsertAttributeDefinition(attributeDefinition, serviceDefinitionRequest); + } + + if(!(attributeDefinition.getDataType().equals(AttributeDefinition.DataTypeEnum.SINGLEVALUELIST) || attributeDefinition.getDataType().equals(AttributeDefinition.DataTypeEnum.MULTIVALUELIST))){ + List emptyStringList = new ArrayList<>(); + emptyStringList.add(""); + attributeDefinition.setValues(emptyStringList); + } + }); + + } } diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceDefinitionRequestValidator.java b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceDefinitionRequestValidator.java index 86f8debd558..d8e13c5ea69 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceDefinitionRequestValidator.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceDefinitionRequestValidator.java @@ -1,11 +1,8 @@ package org.egov.servicerequest.validators; import org.egov.servicerequest.repository.ServiceDefinitionRequestRepository; -import org.egov.servicerequest.web.models.AttributeDefinition; -import org.egov.servicerequest.web.models.ServiceDefinition; -import org.egov.servicerequest.web.models.ServiceDefinitionCriteria; -import org.egov.servicerequest.web.models.ServiceDefinitionRequest; -import org.egov.servicerequest.web.models.ServiceDefinitionSearchRequest; +import org.egov.servicerequest.repository.ServiceRequestRepository; +import org.egov.servicerequest.web.models.*; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -18,14 +15,7 @@ import java.util.Set; import java.util.regex.Pattern; -import static org.egov.servicerequest.error.ErrorCode.ATTRIBUTE_CODE_UNIQUENESS_ERR_CODE; -import static org.egov.servicerequest.error.ErrorCode.ATTRIBUTE_CODE_UNIQUENESS_ERR_MSG; -import static org.egov.servicerequest.error.ErrorCode.INVALID_ATTRIBUTE_DEFINITION_ERR_CODE; -import static org.egov.servicerequest.error.ErrorCode.INVALID_ATTRIBUTE_DEFINITION_ERR_MSG; -import static org.egov.servicerequest.error.ErrorCode.INVALID_REGEX_ERR_CODE; -import static org.egov.servicerequest.error.ErrorCode.INVALID_REGEX_ERR_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_DEFINITION_ALREADY_EXISTS_ERR_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_DEFINITION_ALREADY_EXISTS_ERR_MSG; +import static org.egov.servicerequest.error.ErrorCode.*; @Component public class ServiceDefinitionRequestValidator { @@ -33,6 +23,10 @@ public class ServiceDefinitionRequestValidator { @Autowired private ServiceDefinitionRequestRepository serviceDefinitionRequestRepository; + @Autowired + private ServiceRequestRepository serviceRequestRepository; + + public void validateServiceDefinitionRequest(ServiceDefinitionRequest serviceDefinitionRequest){ ServiceDefinition serviceDefinition = serviceDefinitionRequest.getServiceDefinition(); @@ -87,16 +81,57 @@ private void validateAttributeDefinitionUniqueness(ServiceDefinition serviceDefi } private void validateServiceDefinitionExistence(ServiceDefinition serviceDefinition) { - List serviceDefinitionList = serviceDefinitionRequestRepository.getServiceDefinitions(ServiceDefinitionSearchRequest.builder().serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().tenantId(serviceDefinition.getTenantId()).code(Collections.singletonList(serviceDefinition.getCode())).build()).build()); + List serviceDefinitionList = serviceDefinitionRequestRepository.getServiceDefinitions(ServiceDefinitionSearchRequest.builder().includeDeleted(true).serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().tenantId(serviceDefinition.getTenantId()).code(Collections.singletonList(serviceDefinition.getCode())).build()).build()); if(!CollectionUtils.isEmpty(serviceDefinitionList)){ throw new CustomException(SERVICE_DEFINITION_ALREADY_EXISTS_ERR_CODE, SERVICE_DEFINITION_ALREADY_EXISTS_ERR_MSG); } } - public void validateUpdateRequest(ServiceDefinitionRequest serviceDefinitionRequest) { + private List validateExistence(ServiceDefinition serviceDefinition) { + List serviceDefinitionList = serviceDefinitionRequestRepository. + getServiceDefinitions(ServiceDefinitionSearchRequest.builder() + .includeDeleted(true) + .serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().tenantId(serviceDefinition.getTenantId()).code(Collections.singletonList(serviceDefinition.getCode())).build()).build()); + + //Check if valid service definition exists + if (CollectionUtils.isEmpty(serviceDefinitionList)) { + throw new CustomException(SERVICE_DEFINITION_NOT_EXIST_ERR_CODE, SERVICE_DEFINITION_NOT_EXIST_ERR_MSG); + } + + return serviceDefinitionList; + } + + private void validateService(List serviceDefinition){ + List service = serviceRequestRepository.getService( + ServiceSearchRequest.builder().serviceCriteria( + ServiceCriteria.builder().serviceDefIds(Collections.singletonList(serviceDefinition.get(0).getId())).build() + ).build() + ); + //already a service exists corresponding to service definition + if(!CollectionUtils.isEmpty(service)){ + throw new CustomException(VALID_SERVICE_EXIST_ERR_CODE, VALID_SERVICE_EXIST_ERR_MSG); + } + } + + public ServiceDefinition validateUpdateRequest(ServiceDefinitionRequest serviceDefinitionRequest) { + ServiceDefinition serviceDefinition = serviceDefinitionRequest.getServiceDefinition(); + + //Validate if a Service Definition exists + List serviceDefinitionList = validateExistence(serviceDefinition); + + //Validate if a Service exists corresponding to this Service Definition + validateService(serviceDefinitionList); + + // Validate if all attribute definitions provided as part of service definitions have unique code + validateAttributeDefinitionUniqueness(serviceDefinition); - // TO DO + // Validate values provided in attribute definitions as per data type + validateAttributeValuesAsPerDataType(serviceDefinition); + + // Validate regex values provided in attribute definitions + validateRegex(serviceDefinition); + return serviceDefinitionList.get(0); } } diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java index 66595568bc1..67b2929b36d 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java @@ -21,25 +21,7 @@ import java.util.Map; import java.util.Set; -import static org.egov.servicerequest.error.ErrorCode.INVALID_SIZE_OF_INPUT_CODE; -import static org.egov.servicerequest.error.ErrorCode.INVALID_SIZE_OF_TEXT_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_DATETIME_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_NUMBER_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_SINGLE_VALUE_LIST_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_STRING_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_TEXT_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_MULTIVALUELIST_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_SINGLEVALUELIST_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_VALUES_UNIQUENESS_ERR_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_VALUES_UNIQUENESS_ERR_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_REQUIRED_ATTRIBUTE_NOT_PROVIDED_ERR_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_REQUIRED_ATTRIBUTE_NOT_PROVIDED_ERR_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_UNRECOGNIZED_ATTRIBUTE_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_UNRECOGNIZED_ATTRIBUTE_MSG; +import static org.egov.servicerequest.error.ErrorCode.*; @Slf4j @Component @@ -133,6 +115,10 @@ private void validateAttributeValuesAgainstServiceDefinition(ServiceDefinition s if(!(attributeValue.getValue() instanceof List)){ throw new CustomException(SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE, SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG); } + }else if(attributeCodeVsDataType.get(attributeValue.getAttributeCode()).equals(AttributeDefinition.DataTypeEnum.BOOLEAN)){ + if(!(attributeValue.getValue() instanceof Boolean)){ + throw new CustomException(SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE, SERVICE_REQUEST_ATTRIBUTE_INVALID_BOOLEAN_VALUE_MSG); + } } }); diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java index 59c32cf913b..62616b6b677 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java @@ -41,7 +41,7 @@ public class AttributeDefinition { @JsonProperty("code") @NotNull - @Size(min = 2, max = 64) + @Size(min = 2, max = 256) private String code = null; /** @@ -50,6 +50,8 @@ public class AttributeDefinition { public enum DataTypeEnum { STRING("String"), + BOOLEAN("Boolean"), + NUMBER("Number"), TEXT("Text"), @@ -112,7 +114,7 @@ public static DataTypeEnum fromValue(String text) { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalDetails") + @JsonProperty("additionalFields") private Object additionalDetails = null; diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java index 8aeff4e39f3..98ce105e9b3 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java @@ -41,7 +41,7 @@ public class AttributeValue { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalDetails") + @JsonProperty("additionalFields") private Object additionalDetails = null; diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java index b0348458c15..4fc646ca8ea 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java @@ -51,7 +51,7 @@ public class Service { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalDetails") + @JsonProperty("additionalFields") private Object additionalDetails = null; @JsonProperty("accountId") diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java index e91eeedf541..01b9b31fac9 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java @@ -35,7 +35,7 @@ public class ServiceDefinition { @JsonProperty("code") @NotNull - @Size(min = 2, max = 64) + @Size(min = 2, max = 256) private String code = null; @JsonProperty("isActive") @@ -50,7 +50,7 @@ public class ServiceDefinition { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalDetails") + @JsonProperty("additionalFields") private Object additionalDetails = null; @JsonProperty("clientId") diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionSearchRequest.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionSearchRequest.java index 82af972de54..1971656a6c8 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionSearchRequest.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionSearchRequest.java @@ -33,5 +33,6 @@ public class ServiceDefinitionSearchRequest { @Valid private Pagination pagination = null; - + @JsonProperty("includeDeleted") + private boolean includeDeleted = false; } diff --git a/core-services/service-request/src/main/resources/application.properties b/core-services/service-request/src/main/resources/application.properties index b08e73fc128..a3fdc45c3f2 100644 --- a/core-services/service-request/src/main/resources/application.properties +++ b/core-services/service-request/src/main/resources/application.properties @@ -48,6 +48,7 @@ egov.service.request.max.limit=100 # Kafka topics egov.service.definition.create.topic=save-service-definition egov.service.create.topic=save-service +egov.service.definition.update.topic=update-service-definition # String input size configuration egov.max.string.input.size=8192 \ No newline at end of file diff --git a/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql b/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql new file mode 100644 index 00000000000..ed8ce4007ca --- /dev/null +++ b/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql @@ -0,0 +1,9 @@ +-- Migration script to alter the length of 'code' column in both tables to 256 + +-- Update eg_service_definition table +ALTER TABLE eg_service_definition +ALTER COLUMN code TYPE character varying(256); + +-- Update eg_service_attribute_definition table +ALTER TABLE eg_service_attribute_definition +ALTER COLUMN code TYPE character varying(256); diff --git a/core-services/service-request/src/main/resources/service-request-persister.yml b/core-services/service-request/src/main/resources/service-request-persister.yml index 10fc9ce8702..22bcf13539c 100644 --- a/core-services/service-request/src/main/resources/service-request-persister.yml +++ b/core-services/service-request/src/main/resources/service-request-persister.yml @@ -8,72 +8,68 @@ serviceMaps: queryMaps: - query: INSERT INTO eg_service_definition(id, tenantid, code, isactive, createdby, lastmodifiedby, createdtime, lastmodifiedtime, additionaldetails, clientid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); - basePath: $.serviceDefinition + basePath: $.ServiceDefinition jsonMaps: - - jsonPath: $.serviceDefinition.id + - jsonPath: $.ServiceDefinition.id - - jsonPath: $.serviceDefinition.tenantId + - jsonPath: $.ServiceDefinition.tenantId - - jsonPath: $.serviceDefinition.code + - jsonPath: $.ServiceDefinition.code - - jsonPath: $.serviceDefinition.isActive + - jsonPath: $.ServiceDefinition.isActive - - jsonPath: $.serviceDefinition.auditDetails.createdBy + - jsonPath: $.ServiceDefinition.auditDetails.createdBy - - jsonPath: $.serviceDefinition.auditDetails.lastModifiedBy + - jsonPath: $.ServiceDefinition.auditDetails.lastModifiedBy - - jsonPath: $.serviceDefinition.auditDetails.createdTime + - jsonPath: $.ServiceDefinition.auditDetails.createdTime - - jsonPath: $.serviceDefinition.auditDetails.lastModifiedTime + - jsonPath: $.ServiceDefinition.auditDetails.lastModifiedTime - - jsonPath: $.serviceDefinition.additionalDetails + - jsonPath: $.ServiceDefinition.additionalDetails type: JSON dbType: JSONB - - jsonPath: $.serviceDefinition.clientId + - jsonPath: $.ServiceDefinition.clientId - query: INSERT INTO eg_service_attribute_definition(id, referenceid, tenantid, code, datatype, "values", isactive, required, regex, "order", createdby, lastmodifiedby, createdtime, lastmodifiedtime, additionaldetails) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); - basePath: $.serviceDefinition.attributes.* + basePath: $.ServiceDefinition.attributes.* jsonMaps: - - jsonPath: $.serviceDefinition.attributes.*.id + - jsonPath: $.ServiceDefinition.attributes.*.id - - jsonPath: $.serviceDefinition.attributes.*.referenceId + - jsonPath: $.ServiceDefinition.attributes.*.referenceId - - jsonPath: $.serviceDefinition.attributes.*.tenantId + - jsonPath: $.ServiceDefinition.attributes.*.tenantId - - jsonPath: $.serviceDefinition.attributes.*.code + - jsonPath: $.ServiceDefinition.attributes.*.code - - jsonPath: $.serviceDefinition.attributes.*.dataType + - jsonPath: $.ServiceDefinition.attributes.*.dataType - - jsonPath: $.serviceDefinition.attributes.*.values + - jsonPath: $.ServiceDefinition.attributes.*.values type: ARRAY dbType: STRING - - jsonPath: $.serviceDefinition.attributes.*.isActive + - jsonPath: $.ServiceDefinition.attributes.*.isActive - - jsonPath: $.serviceDefinition.attributes.*.required + - jsonPath: $.ServiceDefinition.attributes.*.required - - jsonPath: $.serviceDefinition.attributes.*.regex + - jsonPath: $.ServiceDefinition.attributes.*.regex - - jsonPath: $.serviceDefinition.attributes.*.order + - jsonPath: $.ServiceDefinition.attributes.*.order - - jsonPath: $.serviceDefinition.attributes.*.auditDetails.createdBy + - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.createdBy - - jsonPath: $.serviceDefinition.attributes.*.auditDetails.lastModifiedBy + - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedBy - - jsonPath: $.serviceDefinition.attributes.*.auditDetails.createdTime + - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.createdTime - - jsonPath: $.serviceDefinition.attributes.*.auditDetails.lastModifiedTime + - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedTime - - jsonPath: $.serviceDefinition.attributes.*.additionalDetails + - jsonPath: $.ServiceDefinition.attributes.*.additionalDetails type: JSON dbType: JSONB - - - - - version: 1.0 description: Persists service details in service table fromTopic: save-service @@ -82,54 +78,135 @@ serviceMaps: - query: INSERT INTO eg_service(id, tenantid, servicedefid, referenceid, createdby, lastmodifiedby, createdtime, lastmodifiedtime, additionaldetails, accountid, clientid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); - basePath: $.service + basePath: $.Service jsonMaps: - - jsonPath: $.service.id + - jsonPath: $.Service.id - - jsonPath: $.service.tenantId + - jsonPath: $.Service.tenantId - - jsonPath: $.service.serviceDefId + - jsonPath: $.Service.serviceDefId - - jsonPath: $.service.referenceId + - jsonPath: $.Service.referenceId - - jsonPath: $.service.auditDetails.createdBy + - jsonPath: $.Service.auditDetails.createdBy - - jsonPath: $.service.auditDetails.lastModifiedBy + - jsonPath: $.Service.auditDetails.lastModifiedBy - - jsonPath: $.service.auditDetails.createdTime + - jsonPath: $.Service.auditDetails.createdTime - - jsonPath: $.service.auditDetails.lastModifiedTime + - jsonPath: $.Service.auditDetails.lastModifiedTime - - jsonPath: $.service.additionalDetails + - jsonPath: $.Service.additionalDetails type: JSON dbType: JSONB - - jsonPath: $.service.accountId + - jsonPath: $.Service.accountId - - jsonPath: $.service.clientId + - jsonPath: $.Service.clientId - query: INSERT INTO eg_service_attribute_value(id, referenceid, attributecode, value, createdby, lastmodifiedby, createdtime, lastmodifiedtime, additionaldetails) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); - basePath: $.service.attributes.* + basePath: $.Service.attributes.* + jsonMaps: + - jsonPath: $.Service.attributes.*.id + + - jsonPath: $.Service.attributes.*.referenceId + + - jsonPath: $.Service.attributes.*.attributeCode + + - jsonPath: $.Service.attributes.*.value + type: JSON + dbType: JSONB + + - jsonPath: $.Service.attributes.*.auditDetails.createdBy + + - jsonPath: $.Service.attributes.*.auditDetails.lastModifiedBy + + - jsonPath: $.Service.attributes.*.auditDetails.createdTime + + - jsonPath: $.Service.attributes.*.auditDetails.lastModifiedTime + + - jsonPath: $.Service.attributes.*.additionalDetails + type: JSON + dbType: JSONB + + + - version: 1.0 + description: Update Service Definition + fromTopic: update-service-definition + isTransaction: true + queryMaps: + + - query: UPDATE eg_service_definition SET lastmodifiedby = ?, lastmodifiedtime = ?, isactive = ?, additionaldetails = ? WHERE id = ? + basePath: $.ServiceDefinition + jsonMaps: + - jsonPath: $.ServiceDefinition.auditDetails.lastModifiedBy + + - jsonPath: $.ServiceDefinition.auditDetails.lastModifiedTime + + - jsonPath: $.ServiceDefinition.isActive + + - jsonPath: $.ServiceDefinition.additionalDetails + type: JSON + dbType: JSONB + + - jsonPath: $.ServiceDefinition.id + + - query: INSERT INTO eg_service_attribute_definition(id, referenceid, tenantid, code, datatype, "values", isactive, required, regex, "order", createdby, lastmodifiedby, createdtime, lastmodifiedtime, additionaldetails) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET datatype=?, "values"=?, isactive=?, required=?, regex=?, "order"=?, lastmodifiedby=?, lastmodifiedtime=?, additionaldetails=?; + basePath: $.ServiceDefinition.attributes.* jsonMaps: - - jsonPath: $.service.attributes.*.id + - jsonPath: $.ServiceDefinition.attributes.*.id + + - jsonPath: $.ServiceDefinition.attributes.*.referenceId + + - jsonPath: $.ServiceDefinition.attributes.*.tenantId + + - jsonPath: $.ServiceDefinition.attributes.*.code + + - jsonPath: $.ServiceDefinition.attributes.*.dataType + + - jsonPath: $.ServiceDefinition.attributes.*.values + type: ARRAY + dbType: STRING - - jsonPath: $.service.attributes.*.referenceId + - jsonPath: $.ServiceDefinition.attributes.*.isActive - - jsonPath: $.service.attributes.*.attributeCode + - jsonPath: $.ServiceDefinition.attributes.*.required - - jsonPath: $.service.attributes.*.value + - jsonPath: $.ServiceDefinition.attributes.*.regex + + - jsonPath: $.ServiceDefinition.attributes.*.order + + - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.createdBy + + - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedBy + + - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.createdTime + + - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedTime + + - jsonPath: $.ServiceDefinition.attributes.*.additionalDetails type: JSON dbType: JSONB - - jsonPath: $.service.attributes.*.auditDetails.createdBy + - jsonPath: $.ServiceDefinition.attributes.*.dataType + + - jsonPath: $.ServiceDefinition.attributes.*.values + type: ARRAY + dbType: STRING + + - jsonPath: $.ServiceDefinition.attributes.*.isActive + + - jsonPath: $.ServiceDefinition.attributes.*.required + + - jsonPath: $.ServiceDefinition.attributes.*.regex - - jsonPath: $.service.attributes.*.auditDetails.lastModifiedBy + - jsonPath: $.ServiceDefinition.attributes.*.order - - jsonPath: $.service.attributes.*.auditDetails.createdTime + - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedBy - - jsonPath: $.service.attributes.*.auditDetails.lastModifiedTime + - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedTime - - jsonPath: $.service.attributes.*.additionalDetails + - jsonPath: $.ServiceDefinition.attributes.*.additionalDetails type: JSON dbType: JSONB \ No newline at end of file diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index 1eb0038656a..b0a2d7d2cad 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.20-SNAPSHOT org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.23-SNAPSHOT compile diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java b/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java index 482ac988b98..2d6b0fd9a6a 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java @@ -5,6 +5,7 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilitySearch; import org.egov.common.producer.Producer; @@ -23,6 +24,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @@ -35,7 +37,7 @@ public FacilityRepository(Producer producer, NamedParameterJdbcTemplate namedPar facilityRowMapper, Optional.of("facility")); } - public List findById(List ids, String columnName, Boolean includeDeleted) { + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { List objFound = findInCache(ids); if (!includeDeleted) { objFound = objFound.stream() @@ -48,7 +50,7 @@ public List findById(List ids, String columnName, Boolean incl .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); if (ids.isEmpty()) { - return objFound; + return SearchResponse.builder().response(objFound).build(); } } @@ -61,10 +63,12 @@ public List findById(List ids, String columnName, Boolean incl objFound.addAll(this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper)); putInCache(objFound); - return objFound; + + /*The totalCount is being set automatically through the builder method.*/ + return SearchResponse.builder().response(objFound).build(); } - public List find(FacilitySearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + public SearchResponse find(FacilitySearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM facility f LEFT JOIN address a ON f.addressid = a.id"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -83,12 +87,17 @@ public List find(FacilitySearch searchObject, Integer limit, Integer o if (lastChangedSince != null) { query = query + "and lastModifiedTime>=:lastModifiedTime "; } - query = query + "ORDER BY f.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + " LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); - return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + List facilities = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + + return SearchResponse.builder().response(facilities).totalCount(totalCount).build(); } } diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index 3517293adcf..73276c91d88 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.facility.Address; import org.egov.common.models.facility.AddressType; diff --git a/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java b/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java index 769aae4b725..76ceb67033d 100644 --- a/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java +++ b/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java @@ -1,13 +1,16 @@ package org.egov.facility.service; +import io.micrometer.core.instrument.search.Search; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; import org.egov.common.models.facility.FacilityRequest; import org.egov.common.models.facility.FacilitySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.validator.Validator; import org.egov.facility.config.FacilityConfiguration; import org.egov.facility.repository.FacilityRepository; @@ -173,23 +176,27 @@ public List delete(FacilityBulkRequest request, boolean isBulk) { return validEntities; } - public List search(FacilitySearchRequest facilitySearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(FacilitySearchRequest facilitySearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("starting search method for facility"); String idFieldName = getIdFieldName(facilitySearchRequest.getFacility()); if (isSearchByIdOnly(facilitySearchRequest.getFacility(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(facilitySearchRequest.getFacility())), facilitySearchRequest.getFacility()); - return facilityRepository.findById(ids, idFieldName, includeDeleted).stream() + SearchResponse searchResponse = facilityRepository.findById(ids, idFieldName, includeDeleted); + List facilities = searchResponse.getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + searchResponse.setResponse(facilities); + + return searchResponse; } log.info("completed search method for facility"); diff --git a/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java b/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java index c666d6b3264..2857a038490 100644 --- a/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java +++ b/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java @@ -50,7 +50,7 @@ public Map> validate(FacilityBulkRequest request) { Map eMap = getIdToObjMap(validEntities, idMethod); if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); - List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false); + List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false).getResponse(); List nonExistentEntities = checkNonExistentEntities(eMap, existingEntities, idMethod); nonExistentEntities.forEach(facility -> { diff --git a/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java b/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java index df76ac89fe4..17adda2b3f2 100644 --- a/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java +++ b/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java @@ -47,7 +47,7 @@ public Map> validate(FacilityBulkRequest request) { Map eMap = getIdToObjMap(validEntities, idMethod); if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); - List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false); + List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); entitiesWithMismatchedRowVersion.forEach(facility -> { diff --git a/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java b/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java index 3ca37071ca8..67de20615b1 100644 --- a/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java +++ b/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java @@ -8,6 +8,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; @@ -111,7 +112,7 @@ public ResponseEntity facilityV1SearchPost( @Valid @ModelAttribute URLParams urlParams, @ApiParam(value = "Details for existing facility.", required = true) @Valid @RequestBody FacilitySearchRequest request ) throws Exception { - List facilities = facilityService.search( + SearchResponse searchResponse = facilityService.search( request, urlParams.getLimit(), urlParams.getOffset(), @@ -119,7 +120,9 @@ public ResponseEntity facilityV1SearchPost( urlParams.getLastChangedSince(), urlParams.getIncludeDeleted()); FacilityBulkResponse response = FacilityBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).facilities(facilities).build(); + .createResponseInfo(request.getRequestInfo(), true)) + .facilities(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java b/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java index a6e8c05f7c1..06955011bc0 100644 --- a/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java +++ b/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java @@ -1,8 +1,10 @@ package org.egov.facility.validator; import org.egov.common.models.Error; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; +import org.egov.common.models.household.Household; import org.egov.facility.helper.FacilityBulkRequestTestBuilder; import org.egov.facility.helper.FacilityTestBuilder; import org.egov.facility.repository.FacilityRepository; @@ -37,7 +39,7 @@ class NonExistentEntityValidatorTest { void shouldAddToErrorDetailsMapIfEntityNotFound() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().build()); Map> errorDetailsMap = fNonExistentValidator.validate(request); @@ -49,7 +51,9 @@ void shouldAddToErrorDetailsMapIfEntityNotFound() { void shouldNotAddToErrorDetailsMapIfEntityFound() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())); + .thenReturn(SearchResponse.builder(). + response(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())) + .build()); Map> errorDetailsMap = fNonExistentValidator.validate(request); diff --git a/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java b/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java index 1f44a89f94a..52f92421c49 100644 --- a/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java +++ b/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java @@ -1,6 +1,7 @@ package org.egov.facility.validator; import org.egov.common.models.Error; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; import org.egov.facility.helper.FacilityBulkRequestTestBuilder; @@ -39,7 +40,9 @@ void shouldAddToErrorDetailsIfRowVersionMismatchFound() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); request.getFacilities().get(0).setRowVersion(2); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())); + .thenReturn(SearchResponse.builder() + .response(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())) + .build()); Map> errorDetailsMap = fRowVersionValidator.validate(request); @@ -51,7 +54,8 @@ void shouldAddToErrorDetailsIfRowVersionMismatchFound() { void shouldNotAddToErrorDetailsIfRowVersionSimilar() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())); + .thenReturn(SearchResponse.builder() + .response(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())).build()); Map> errorDetailsMap = fRowVersionValidator.validate(request); diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 84ca10da8d3..d99c514e51b 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -53,12 +53,12 @@ org.egov.common health-services-common - 1.0.18-SNAPSHOT + 1.0.19-SNAPSHOT org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.22-SNAPSHOT compile diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index e08aeef5d17..703b5521652 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -264,14 +264,14 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi query = query + "AND lastModifiedTime>=:lastModifiedTime "; } if (searchObject.getRoleCodes() != null && !searchObject.getRoleCodes().isEmpty()) { - query = query + "AND roles @> '["; + query = query + "AND ("; for (int i = 0; i < searchObject.getRoleCodes().size(); i++) { - query = query + "{\"code\": \"" + searchObject.getRoleCodes().get(i) + "\"}"; + query = query + "roles @> '[{\"code\": \"" + searchObject.getRoleCodes().get(i) + "\"}]'"; if (i != searchObject.getRoleCodes().size() - 1) { - query = query + ","; + query = query + " OR "; // Add OR between conditions } } - query = query + "]' "; + query = query + ") "; } if (searchObject.getUsername() != null) { diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java index 48396c74988..fe50b9c2d6c 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java @@ -1,14 +1,14 @@ package org.egov.individual.repository.rowmapper; -import digit.models.coremodels.AuditDetails; +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.egov.common.contract.models.AuditDetails; +import org.egov.common.models.core.Boundary; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.AddressType; -import org.egov.common.models.core.Boundary; import org.springframework.jdbc.core.RowMapper; -import java.sql.ResultSet; -import java.sql.SQLException; - public class AddressRowMapper implements RowMapper
{ @Override public Address mapRow(ResultSet resultSet, int i) throws SQLException { diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IdentifierRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IdentifierRowMapper.java index 4cdbc036fa9..89244c90588 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IdentifierRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IdentifierRowMapper.java @@ -1,12 +1,12 @@ package org.egov.individual.repository.rowmapper; -import digit.models.coremodels.AuditDetails; -import org.egov.common.models.individual.Identifier; -import org.springframework.jdbc.core.RowMapper; - import java.sql.ResultSet; import java.sql.SQLException; +import org.egov.common.contract.models.AuditDetails; +import org.egov.common.models.individual.Identifier; +import org.springframework.jdbc.core.RowMapper; + public class IdentifierRowMapper implements RowMapper { @Override public Identifier mapRow(ResultSet resultSet, int i) throws SQLException { diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index be0f5387bd4..26ea439cd69 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -6,8 +6,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; -import digit.models.coremodels.user.enums.UserType; +import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.user.enums.UserType; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.individual.BloodGroup; import org.egov.common.models.individual.Gender; diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/SkillRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/SkillRowMapper.java index c658d9e98e6..bacdae2e64a 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/SkillRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/SkillRowMapper.java @@ -1,12 +1,12 @@ package org.egov.individual.repository.rowmapper; -import digit.models.coremodels.AuditDetails; -import org.egov.common.models.individual.Skill; -import org.springframework.jdbc.core.RowMapper; - import java.sql.ResultSet; import java.sql.SQLException; +import org.egov.common.contract.models.AuditDetails; +import org.egov.common.models.individual.Skill; +import org.springframework.jdbc.core.RowMapper; + public class SkillRowMapper implements RowMapper { @Override public Skill mapRow(ResultSet resultSet, int i) throws SQLException { diff --git a/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java b/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java index 7ea9daff08e..45c972c644e 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java @@ -9,8 +9,8 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; -import digit.models.coremodels.AuditDetails; import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.Identifier; diff --git a/health-services/individual/src/main/java/org/egov/individual/service/NotificationService.java b/health-services/individual/src/main/java/org/egov/individual/service/NotificationService.java index 8cb45638e6c..88767bb5bb4 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/NotificationService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/NotificationService.java @@ -1,11 +1,15 @@ package org.egov.individual.service; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.jayway.jsonpath.JsonPath; -import digit.models.coremodels.RequestInfoWrapper; -import digit.models.coremodels.SMSRequest; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.models.RequestInfoWrapper; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.SMSRequest; import org.egov.common.models.individual.IndividualRequest; import org.egov.individual.Constants; import org.egov.individual.config.IndividualProperties; @@ -15,10 +19,6 @@ import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import static org.egov.individual.Constants.INDIVIDUAL_CREATE_LOCALIZATION_CODE; import static org.egov.individual.Constants.INDIVIDUAL_UPDATE_LOCALIZATION_CODE; diff --git a/health-services/libraries/health-services-common/pom.xml b/health-services/libraries/health-services-common/pom.xml index 8f5e0d4fae9..5bdd15176c3 100644 --- a/health-services/libraries/health-services-common/pom.xml +++ b/health-services/libraries/health-services-common/pom.xml @@ -8,7 +8,7 @@ health-services-common jar health-services-common - 1.0.18-SNAPSHOT + 1.0.20-SNAPSHOT Shared classes among services @@ -85,11 +85,6 @@ org.springframework.boot spring-boot-starter-jdbc - - org.egov.services - digit-models - 1.0.0-SNAPSHOT - org.egov.services tracer @@ -120,7 +115,13 @@ org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.23-dev-SNAPSHOT + compile + + + org.egov + mdms-client + 2.9.0-SNAPSHOT compile diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java index 537a82400cc..269a15e449d 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java @@ -4,6 +4,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.models.core.SearchResponse; import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; @@ -23,6 +24,7 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; @@ -236,6 +238,52 @@ public void putInCache(List objects, String key) { cacheByKey(objects, key); } + /** + * Finds entities based on search criteria, also returns the count of entities found. + * + * @param searchObject The object containing search criteria. + * @param limit The maximum number of entities to return. + * @param offset The offset for pagination. + * @param tenantId The tenant ID to filter entities. + * @param lastChangedSince The timestamp for last modified entities. + * @param includeDeleted Flag to include deleted entities in the search result. + * @return A list of entities found based on the search criteria with total count. + * @throws QueryBuilderException If an error occurs while building the query. + */ + public SearchResponse findWithCount(Object searchObject, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws QueryBuilderException { + String query = selectQueryBuilder.build(searchObject, tableName); + query += " AND tenantId=:tenantId "; + if (query.contains(tableName + " AND")) { + query = query.replace(tableName + " AND", tableName + " WHERE"); + } + if (Boolean.FALSE.equals(includeDeleted)) { + query += "AND isDeleted=:isDeleted "; + } + if (lastChangedSince != null) { + query += "AND lastModifiedTime>=:lastModifiedTime "; + } + query += "ORDER BY id ASC"; + Map paramsMap = selectQueryBuilder.getParamsMap(); + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, namedParameterJdbcTemplate); + + query += " LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + + List resultantList = namedParameterJdbcTemplate.query(query, paramsMap, rowMapper); + + return SearchResponse.builder().response(resultantList).totalCount(totalCount).build(); + } + /** * Finds entities based on search criteria. * diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/helper/AuditDetailsTestBuilder.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/helper/AuditDetailsTestBuilder.java index 984882b8310..efce9048d3f 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/helper/AuditDetailsTestBuilder.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/helper/AuditDetailsTestBuilder.java @@ -1,6 +1,6 @@ package org.egov.common.helper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; public class AuditDetailsTestBuilder { private AuditDetails.AuditDetailsBuilder builder; diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java index c693e8f6788..25b167a227d 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java @@ -1,9 +1,9 @@ package org.egov.common.service; -import digit.models.coremodels.IdGenerationRequest; -import digit.models.coremodels.IdGenerationResponse; -import digit.models.coremodels.IdRequest; -import digit.models.coremodels.IdResponse; +import org.egov.common.contract.idgen.IdGenerationRequest; +import org.egov.common.contract.idgen.IdGenerationResponse; +import org.egov.common.contract.idgen.IdRequest; +import org.egov.common.contract.idgen.IdResponse; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.tracer.model.CustomException; diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/UserService.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/UserService.java index 77be02a6504..204e7fa6fdb 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/UserService.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/UserService.java @@ -1,7 +1,7 @@ package org.egov.common.service; -import digit.models.coremodels.UserDetailResponse; -import digit.models.coremodels.UserSearchRequest; +import org.egov.common.contract.user.UserDetailResponse; +import org.egov.common.contract.user.UserSearchRequest; import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.User; import org.egov.common.http.client.ServiceRequestClient; diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java index 927a05044ca..c72e7a7563c 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java @@ -23,7 +23,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.common.ds.Tuple; diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/helpers/SomeObject.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/helpers/SomeObject.java index 1aa90f6ba01..68cdf3b6981 100644 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/helpers/SomeObject.java +++ b/health-services/libraries/health-services-common/src/test/java/org/egov/common/helpers/SomeObject.java @@ -1,6 +1,6 @@ package org.egov.common.helpers; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/helpers/SomeObjectWithClientRefId.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/helpers/SomeObjectWithClientRefId.java index 268d32b9cd0..3f54d554a32 100644 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/helpers/SomeObjectWithClientRefId.java +++ b/health-services/libraries/health-services-common/src/test/java/org/egov/common/helpers/SomeObjectWithClientRefId.java @@ -1,6 +1,6 @@ package org.egov.common.helpers; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java index b50d359d969..e2f01d42f18 100644 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java +++ b/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import lombok.Builder; import lombok.Data; import org.egov.common.contract.request.RequestInfo; diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index 6ca95c3fe47..dc4e4c878ca 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.egov.common health-services-models - 1.0.21-SNAPSHOT + 1.0.23-SNAPSHOT 17 ${java.version} @@ -24,11 +24,6 @@ jackson-datatype-jsr310 2.14.2 - - org.egov.services - digit-models - 1.0.0-SNAPSHOT - org.egov.services tracer diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java index f3632bb819b..434d2c52f9e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java @@ -1,10 +1,9 @@ package org.egov.common.models.core; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java index f68ea5cea75..4c47b940b45 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java @@ -1,18 +1,17 @@ package org.egov.common.models.core; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; +import org.egov.common.contract.models.AuditDetails; @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java index e816f6cd3ce..d9a338d5cde 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java @@ -1,15 +1,14 @@ package org.egov.common.models.core; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Size; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; +import org.egov.common.contract.models.AuditDetails; @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SMSRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SMSRequest.java new file mode 100644 index 00000000000..74371122d5f --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SMSRequest.java @@ -0,0 +1,18 @@ +package org.egov.common.models.core; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class SMSRequest { + private String mobileNumber; + private String message; +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java index 3ea950184ae..e94f3aeab71 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java @@ -1,19 +1,19 @@ package org.egov.common.models.facility; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * AdditionalFields */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java index 3c4d8ba3bf9..0a7a92bf03f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java @@ -1,21 +1,16 @@ package org.egov.common.models.facility; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * Facility */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java index 36c96818a5b..e8dd5de95bf 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java @@ -1,19 +1,19 @@ package org.egov.common.models.facility; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * FacilityBulkRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java index d58d67eba90..e1550174657 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java @@ -1,40 +1,55 @@ package org.egov.common.models.facility; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** - * FacilityResponse + * Represents a bulk response for facilities, including response metadata and a list of facilities. */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class FacilityBulkResponse { + + /** + * Metadata about the API response, including request details and status. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; + /** + * List of facilities returned in the response. + */ @JsonProperty("Facilities") @Valid private List facilities = null; + /** + * Total number of facilities in the response, defaults to 0. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + /** + * Adds a single facility to the list and returns the updated response. + */ public FacilityBulkResponse addFacilityItem(Facility facilityItem) { if (this.facilities == null) { this.facilities = new ArrayList<>(); @@ -42,6 +57,4 @@ public FacilityBulkResponse addFacilityItem(Facility facilityItem) { this.facilities.add(facilityItem); return this; } - } - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java index be7a61eb30d..4ad6fd4f358 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * FacilityRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java index d0642700db3..c211f19fd5c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * FacilityResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java index 6a6924bea67..e079450fc4a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * FacilitySearchRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java index d706a86fcff..9294e57417d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java @@ -1,19 +1,19 @@ package org.egov.common.models.facility; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java index a534fb37cfb..11deb8cbd48 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java @@ -1,19 +1,19 @@ package org.egov.common.models.facility; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java index c38b8ef5b97..a04df2e6c06 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java @@ -1,19 +1,19 @@ package org.egov.common.models.household; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * AdditionalFields */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java index c948934f9c9..ef02f0c2d95 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java @@ -1,10 +1,9 @@ package org.egov.common.models.household; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java index 2452054c4f8..63c982ff07f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java @@ -8,8 +8,8 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; -import org.hibernate.validator.constraints.Range; import org.egov.common.models.core.EgovOfflineModel; +import org.hibernate.validator.constraints.Range; import org.springframework.validation.annotation.Validated; /** diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java index cf1b86cc6d2..77e8498cd3e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java @@ -1,7 +1,13 @@ package org.egov.common.models.household; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,12 +15,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * HouseholdRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java index 3646ac55627..26b8a85f21c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java @@ -1,7 +1,12 @@ package org.egov.common.models.household; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,11 +14,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * HouseholdResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java index c7e016e117d..6e697513777 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java @@ -1,22 +1,16 @@ package org.egov.common.models.household; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * A representation of a household member (already registered as an individual) */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java index 9e45a1f496c..a16cb00a03b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java @@ -1,19 +1,19 @@ package org.egov.common.models.household; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * HouseholdMemberRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java index 529336e2052..df83a9b6221 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java @@ -1,18 +1,18 @@ package org.egov.common.models.household; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * HouseholdMemberResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java index afe2b3a35a2..636be1ea09b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * HouseholdMemberRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java index 4439b053fa2..c00408c8b1f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * HouseholdMemberResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java index 1827c58c249..97c1f03edf5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * HouseholdMemberSearchRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java index 2f97fff1203..bbde10101e2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * HouseholdRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java index 8659cc34bbf..ca82278de1d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * HouseholdResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java index 57e5377b5ca..3a43464d905 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * HouseholdSearchRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java index 9a37607d2ca..a75a0cc4173 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java @@ -1,19 +1,19 @@ package org.egov.common.models.household; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java index 648f7640cbe..4b29d02edf4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java @@ -1,19 +1,19 @@ package org.egov.common.models.household; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java index 2546f7f417e..f7a4703279c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java @@ -1,19 +1,19 @@ package org.egov.common.models.individual; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * AdditionalFields */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java index a6a6a067449..09e5894a88c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java @@ -2,21 +2,20 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.DecimalMax; -import jakarta.validation.constraints.DecimalMin; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java index c6b33f09776..86d86e5c4e7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java @@ -1,10 +1,9 @@ package org.egov.common.models.individual; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java index 213a67a9446..f07b5909530 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java @@ -2,17 +2,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * Identifier */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index e045ff1fea5..1fb620908bc 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -1,26 +1,23 @@ package org.egov.common.models.individual; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - /** * A representation of an Individual. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java index 4810780d4e7..59e954bcd5b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java @@ -1,7 +1,13 @@ package org.egov.common.models.individual; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,12 +15,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * IndividualRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java index 5a185cbaf8d..60647504677 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java @@ -1,7 +1,12 @@ package org.egov.common.models.individual; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,17 +14,11 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** - * IndividualResponse + * IndividualBulkResponse represents the response structure for bulk operations related to individuals. + * It encapsulates the response information, total count of individuals, and a list of individual objects. */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @@ -27,20 +26,35 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class IndividualBulkResponse { + /** + * Metadata about the API response, including details like request status and other information. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; + /** + * Total count of individual records in the response, defaults to 0 if not specified. + */ @JsonProperty("TotalCount") @Valid @Builder.Default private Long totalCount = 0L; - + + /** + * List of individual records returned in the response. + */ @JsonProperty("Individual") @Valid private List individual = null; + /** + * Adds a single individual record to the list and returns the updated response. + * + * @param individualItem The individual record to add to the list. + * @return The updated IndividualBulkResponse instance. + */ public IndividualBulkResponse addIndividualItem(Individual individualItem) { if (this.individual == null) { this.individual = new ArrayList<>(); @@ -48,6 +62,4 @@ public IndividualBulkResponse addIndividualItem(Individual individualItem) { this.individual.add(individualItem); return this; } - } - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java index c8b7927e036..74d61e71bcb 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * IndividualRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java index e782b4af9a8..20b21747fe1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * IndividualResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java index 7a75ea01913..895ed4c19f7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java @@ -2,14 +2,13 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.constraints.Size; - /** * Name */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java index 58b905a8522..682ddccdedd 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java @@ -2,17 +2,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * Identifier */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java index ea435d9fac9..07ad2e70c02 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java @@ -1,18 +1,18 @@ package org.egov.common.models.individual; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.user.enums.UserType; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.contract.user.enums.UserType; import org.egov.common.models.core.Role; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Size; -import java.util.List; - @Data @AllArgsConstructor @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java index 87d1cd3ea63..7ae3f2fcc85 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java @@ -1,19 +1,19 @@ package org.egov.common.models.product; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * AdditionalFields */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java index f27a52cf429..8c20a6f160b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java @@ -1,10 +1,9 @@ package org.egov.common.models.product; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java index afa12e20be2..71d61bde9bc 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java @@ -2,19 +2,15 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * Product */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java index 5b209a65ff9..2381054bb30 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java @@ -1,7 +1,13 @@ package org.egov.common.models.product; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,12 +15,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * ProductRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java index 52865f39251..871fcecfe3e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java @@ -1,7 +1,12 @@ package org.egov.common.models.product; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,11 +14,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * ProductResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java index 1f32dad0bf8..d42833b05e9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * ProductSearchRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java index 6f7e34e6b5e..969500ae70b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java @@ -1,10 +1,9 @@ package org.egov.common.models.product; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java index e9d815128a9..4e5a644fe8e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java @@ -1,7 +1,13 @@ package org.egov.common.models.product; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,12 +15,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * ProductVariantRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java index 5584a534753..9120c1e686a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java @@ -1,7 +1,12 @@ package org.egov.common.models.product; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,11 +14,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * ProductVariantResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java index 880b52f0d1a..58da166d7d1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * ProductVariantSearchRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java index 3970c1927d2..b15c8ac157a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java @@ -2,14 +2,13 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.constraints.NotNull; - /** * ProjectProductVariant */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java index 2b2ed233edc..f58ffb7190d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java @@ -1,8 +1,13 @@ package org.egov.common.models.product; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -10,11 +15,6 @@ import org.egov.common.contract.request.Role; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java index 5c89828c693..9876d411fc3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java @@ -1,8 +1,13 @@ package org.egov.common.models.product; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -10,11 +15,6 @@ import org.egov.common.contract.request.Role; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java index 819eb9def0c..9dd8ccf7868 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java @@ -1,19 +1,19 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * AdditionalFields */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java index a928b1cadbf..97a9dfd4c27 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java @@ -3,6 +3,11 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -10,12 +15,6 @@ import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.DecimalMax; -import jakarta.validation.constraints.DecimalMin; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java index a6167611a94..ab1bbb52368 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java @@ -1,7 +1,13 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,12 +15,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * BeneficiaryRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java index 06c6081b71b..fbd9c84e842 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java @@ -1,7 +1,12 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,11 +14,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * BeneficiaryResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java index cb1e4462721..a40eba1c47c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * BeneficiaryRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java index 0b95acf2dc8..49b341a332b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * BeneficiaryResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java index 9ca9e718d78..112bca6f03d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * BeneficiarySearchRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java index 1eb86b7c89f..388c1f52a66 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java @@ -3,18 +3,17 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * A Object holds the basic data for a Trade License */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java index 58360cdaf8e..4bb2c5052b1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java @@ -1,10 +1,9 @@ package org.egov.common.models.project; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java index 586ff410489..b01995957ba 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java @@ -1,20 +1,20 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.egov.common.contract.models.AuditDetails; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import java.util.ArrayList; -import java.util.List; - /** * The purpose of this object to define the Project for a geography and period */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java index 6c899a34765..514c5413422 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java @@ -1,23 +1,18 @@ package org.egov.common.models.project; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * A representation of the registration of an entity to a Project. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java index cd1af9dfcb0..846ba1dcf38 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java @@ -1,8 +1,14 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -10,12 +16,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * ProjectStaffRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java index d2481b16298..38d1df9eafa 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java @@ -1,6 +1,12 @@ package org.egov.common.models.project; + +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -8,35 +14,47 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** - * ProjectFacilityResponse + * Represents a bulk response for project facilities, including response metadata and a list of facilities. */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class ProjectFacilityBulkResponse { + + /** + * Metadata about the API response, including request details and status. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; + /** + * Total number of project facilities in the response, defaults to 0. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * List of project facilities returned in the response. + */ @JsonProperty("ProjectFacilities") @NotNull @Valid private List projectFacilities = new ArrayList<>(); + /** + * Adds a single project facility to the list and returns the updated response. + */ public ProjectFacilityBulkResponse addProjectFacilityItem(ProjectFacility projectFacilityItem) { this.projectFacilities.add(projectFacilityItem); return this; } } + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java index a985decccef..7c556dc1f0c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * ProjectFacilityRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java index ce862b669c6..5424a2a29f2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * ProjectFacilityResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java index e8841ba5de9..4e07cede298 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java @@ -2,14 +2,13 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.constraints.NotNull; - /** * ProjectProductVariant */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java index da4ae0343e4..f450a99a556 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java @@ -1,7 +1,13 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,12 +15,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * ProjectRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java index 64001b9e278..dbeff61e3f3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java @@ -1,22 +1,17 @@ package org.egov.common.models.project; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * This object defines the mapping of a resource to a project. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java index 26b6c095232..a78ed2a8637 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java @@ -1,7 +1,13 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,12 +15,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * ProjectResourceRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java index e04eb6abd1b..7aef41e322b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java @@ -1,7 +1,12 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,11 +14,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * ProjectResourceResponse */ @@ -37,6 +37,11 @@ public class ProjectResourceBulkResponse { @Valid private List projectResource = new ArrayList<>(); + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + public ProjectResourceBulkResponse addProjectResourceItem(ProjectResource projectResourceItem) { this.projectResource.add(projectResourceItem); return this; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java index d3387b1af96..edfdc4e583d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * ProjectResourceRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java index cc9a7e5c635..465b5cc3774 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * ProjectResourceResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java index 54872c4d5a4..09440ed984f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java @@ -1,7 +1,12 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,11 +14,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * ProjectResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java index 3dc85137b83..8489479b0cd 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java @@ -9,7 +9,6 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.core.ProjectSearchURLParams; import org.springframework.validation.annotation.Validated; /** diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java index 78ecda1fa80..a2775e15997 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java @@ -1,23 +1,16 @@ package org.egov.common.models.project; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - -import lombok.experimental.SuperBuilder; -import org.egov.common.models.core.EgovModel; -import org.springframework.validation.annotation.Validated; - -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; - -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; +import org.springframework.validation.annotation.Validated; /** * This object defines the mapping of a system staff user to a project for a certain period. diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java index c13dc8fcc4b..baaf7d8ef94 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java @@ -1,7 +1,13 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,12 +15,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * ProjectStaffRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java index d73daee5c73..49070e25a94 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java @@ -1,7 +1,12 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,17 +14,10 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** -* ProjectStaffResponse -*/ + * Represents a bulk response for project staff, containing response metadata and a list of staff members. + */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @@ -27,19 +25,38 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class ProjectStaffBulkResponse { + /** + * Metadata about the API response, including request status and other information. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; + /** + * List of project staff members returned in the response. + */ @JsonProperty("ProjectStaff") @NotNull @Valid private List projectStaff = new ArrayList<>(); + /** + * Total number of project staff members in the response, defaults to 0 if not specified. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * Adds a single project staff member to the list and returns the updated response. + * + * @param projectStaffItem The project staff member to add to the list. + * @return The updated ProjectStaffBulkResponse instance. + */ public ProjectStaffBulkResponse addProjectStaffItem(ProjectStaff projectStaffItem) { this.projectStaff.add(projectStaffItem); return this; } } - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java index ec7042c5ee0..37839657cee 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * ProjectStaffRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java index 49403f8dd95..d862684e27a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * ProjectStaffResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java index b428843e9d3..78445bed4a9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java @@ -1,20 +1,20 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * This is the master data to capture the metadata of Project */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java index fa2e4fee092..49078973f0c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java @@ -3,15 +3,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * minimal representation of the Roles in the system to be carried along in UserInfo with RequestInfo meta data. Actual authorization service to extend this to have more role related attributes */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java index 5fe7f7dbf7e..e7152211048 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java @@ -3,12 +3,12 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.egov.common.contract.models.AuditDetails; import org.springframework.validation.annotation.Validated; /** diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java index 87b257e312c..94b89a69685 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java @@ -1,7 +1,13 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,12 +15,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * TaskRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java index c0bbfb8e5f5..673bb8c6d97 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java @@ -1,7 +1,12 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,11 +14,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * TaskResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java index a1d61ed85c1..438ec662d70 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * TaskRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java index 8c798d1ef34..042dee89976 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; @@ -10,6 +9,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.springframework.validation.annotation.Validated; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java index 8baedb1acfa..1ff055ae364 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java @@ -1,7 +1,13 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,12 +15,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * TaskRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java index 4d8c13db362..c63d797d91e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java @@ -1,7 +1,12 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,11 +14,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * TaskResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java index 64274a157ea..c24964729db 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * TaskResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java index dea1ee10e02..bb52da94578 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,9 +11,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * TaskSearchRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java index 1feb9f2518f..9a1aa439694 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java @@ -1,19 +1,19 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java index 57afb18c30f..aa727b72fe9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java @@ -1,19 +1,19 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserServiceResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserServiceResponse.java index a14f952ab02..d4448feec31 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserServiceResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserServiceResponse.java @@ -1,5 +1,8 @@ package org.egov.common.models.project; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,9 +11,6 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.User; -import java.util.ArrayList; -import java.util.List; - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java index 9cdc553bb92..72d8930d21f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java index 2c68467c843..50cd5a9b2ea 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java @@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java index a561ef4f8a4..d8791d66979 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java @@ -13,21 +13,39 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.response.ResponseInfo; +/** + * Represents a bulk response for HF (Health Facility) referrals, containing response metadata and a list of referrals. + */ @Data @NoArgsConstructor @AllArgsConstructor @Builder public class HFReferralBulkResponse { + + /** + * Metadata about the API response, including details such as request status and information. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo; + /** + * List of health facility referrals returned in the response. + */ @JsonProperty("HFReferrals") @NotNull @Valid private List hfReferrals; + /** + * Total number of HF referrals in the response, defaults to 0 if not specified. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + /** * Add a HfReferral item to the list of HfReferrals in the bulk response. * diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java index f9f3041aeb5..cd41a108d8d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java index ef65681acc2..275d45de86c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java @@ -1,19 +1,19 @@ package org.egov.common.models.stock; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * AdditionalFields */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java index f040c0d8a28..39cc0e6f3b1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java @@ -1,10 +1,9 @@ package org.egov.common.models.stock; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java index 1ec63f96c54..fb9ed990e54 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java @@ -1,17 +1,13 @@ package org.egov.common.models.stock; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Builder.Default; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java index 696a7b9e41e..24080a26365 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java @@ -1,19 +1,19 @@ package org.egov.common.models.stock; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * StockRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java index cea7c46b8e5..3ad45bc8ed7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java @@ -1,24 +1,22 @@ package org.egov.common.models.stock; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** - * StockResponse + * Represents a bulk response for stock items, containing response metadata and a list of stock entries. */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @@ -26,20 +24,40 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class StockBulkResponse { + /** + * Metadata about the API response, including details such as request status and information. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; + /** + * List of stock items returned in the response. + */ @JsonProperty("Stock") @NotNull @Valid private List stock = new ArrayList<>(); - + /** + * Total number of stock items in the response, defaults to 0 if not specified. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * Adds a single stock item to the list of stock and returns the updated response. + * + * @param stockItem The stock item to add to the list. + * @return The updated StockBulkResponse instance. + */ public StockBulkResponse addStockItem(Stock stockItem) { this.stock.add(stockItem); return this; } } + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java index b8fc052ce68..b1db836bf5d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java @@ -1,21 +1,16 @@ package org.egov.common.models.stock; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; - /** * StockReconciliation */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java index b9f01d68f98..17eeac712c9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java @@ -1,19 +1,19 @@ package org.egov.common.models.stock; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * StockReconciliationRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java index caea2ead604..bae326d2dd8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java @@ -1,24 +1,22 @@ package org.egov.common.models.stock; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** - * StockReconciliationResponse + * Represents a bulk response for stock reconciliation, containing response metadata and a list of stock reconciliation entries. */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @@ -26,19 +24,38 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class StockReconciliationBulkResponse { + /** + * Metadata about the API response, including details such as request status and information. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; + /** + * List of stock reconciliation items returned in the response. + */ @JsonProperty("StockReconciliation") @NotNull @Valid private List stockReconciliation = new ArrayList<>(); + /** + * Total number of stock reconciliation items in the response, defaults to 0 if not specified. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * Adds a single stock reconciliation item to the list and returns the updated response. + * + * @param stockReconciliationItem The stock reconciliation item to add to the list. + * @return The updated StockReconciliationBulkResponse instance. + */ public StockReconciliationBulkResponse addStockReconciliationItem(StockReconciliation stockReconciliationItem) { this.stockReconciliation.add(stockReconciliationItem); return this; } } - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java index 58845227bf2..2475b989848 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * StockReconciliationRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java index 409223db9ca..3046c8697c9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * StockReconciliationResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java index 6b307ce2d11..d768a5a306e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * StockReconciliationSearchRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java index 10b7f7fde07..b716902e5a6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * StockRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java index 1cea9fc0185..55dadd4834c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * StockResponse */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java index 9f73cb1e00e..8664fc1837f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; - /** * StockSearchRequest */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java index 261bcb9d725..6c582bf37af 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java @@ -1,19 +1,19 @@ package org.egov.common.models.stock; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants. */ diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java index 85edeeef0aa..1c67558b4e3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java @@ -1,19 +1,19 @@ package org.egov.common.models.stock; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server. */ diff --git a/health-services/plan-service/src/main/java/digit/service/PlanValidator.java b/health-services/plan-service/src/main/java/digit/service/PlanValidator.java index cd9a6e9ba5d..aa1656c00b3 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanValidator.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanValidator.java @@ -671,4 +671,4 @@ private void enrichAncestralMaterializedPath(BulkPlanRequest bulkPlanRequest, Li .get(plan.getId())) ); } -} +} \ No newline at end of file diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index fd0b688dcc3..9cb321d57d0 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.18-SNAPSHOT + 1.0.20-dev-SNAPSHOT org.egov.common health-services-models - 1.0.21-SNAPSHOT + 1.0.23-dev-SNAPSHOT compile diff --git a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java index 26759e381e2..67ee5a87af6 100644 --- a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java @@ -222,4 +222,7 @@ public class ProjectConfiguration { @Value("${project.task.no.resource.validation.status}") private List noResourceStatuses; + + @Value("${project.attendance.feature.enabled:true}") + private Boolean isAttendanceFeatureEnabled; } diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java index d602f809b15..219a38458ec 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java @@ -1,9 +1,13 @@ package org.egov.project.repository; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; import org.egov.common.models.project.ProjectFacility; +import org.egov.common.models.project.ProjectFacilitySearch; import org.egov.common.producer.Producer; import org.egov.project.repository.rowmapper.ProjectFacilityRowMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -11,15 +15,16 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository @Slf4j public class ProjectFacilityRepository extends GenericRepository { @Autowired public ProjectFacilityRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, - RedisTemplate redisTemplate, - SelectQueryBuilder selectQueryBuilder, ProjectFacilityRowMapper projectFacilityRowMapper) { + RedisTemplate redisTemplate, + SelectQueryBuilder selectQueryBuilder, ProjectFacilityRowMapper projectFacilityRowMapper) { super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, projectFacilityRowMapper, Optional.of("project_facility")); } -} +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java b/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java index 466c3549af4..4b3aeda7bac 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java +++ b/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java @@ -93,6 +93,18 @@ public String getProjectSearchQuery(List projects, Integer limit, Integ preparedStmtList.add(project.getProjectType()); } + if (StringUtils.isNotBlank(project.getReferenceID())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.referenceId =? "); + preparedStmtList.add(project.getReferenceID()); + } + + if (StringUtils.isNotBlank(project.getParent())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.parent =? "); + preparedStmtList.add(project.getParent()); + } + if (project.getAddress() != null && StringUtils.isNotBlank(project.getAddress().getBoundary())) { addClauseIfRequired(preparedStmtList, queryBuilder); queryBuilder.append(" addr.boundary=? "); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java index b9d3f814d7c..b2fcfb5672a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.project.Document; import org.egov.tracer.model.CustomException; import org.postgresql.util.PGobject; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java index b9ea8babec8..a5a8da51b09 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.UserActionEnum; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java index fa5d72c5dc7..b4cd46201b3 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.project.Address; import org.egov.common.models.project.AddressType; import org.egov.common.models.project.Project; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java index c79c91ed161..663ada6310f 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectBeneficiary; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java index d6433f36db6..3d622db4a42 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectFacility; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java index 34deb79333a..bd6aa793bb6 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java @@ -1,7 +1,7 @@ package org.egov.project.repository.rowmapper; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.project.ProjectProductVariant; import org.egov.common.models.project.ProjectResource; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java index b8625274dfc..a4e1193eed2 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java @@ -1,6 +1,6 @@ package org.egov.project.repository.rowmapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.project.Project; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java index a0ff3d24bcf..169bdc99d40 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectStaff; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index ccff648bd41..406a7419c54 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.Address; import org.egov.common.models.project.AddressType; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java index f9b352a69b4..59477283fec 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java @@ -1,6 +1,6 @@ package org.egov.project.repository.rowmapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.project.Target; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.ResultSetExtractor; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java index 87cab062d9c..1187e1692e6 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.TaskResource; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java index 8a63f0f3c99..57c992ae154 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.UserActionEnum; diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java index f7628318789..9e5e47675bb 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java @@ -1,9 +1,16 @@ package org.egov.project.service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectFacility; import org.egov.common.models.project.ProjectFacilityBulkRequest; import org.egov.common.models.project.ProjectFacilityRequest; @@ -27,12 +34,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.handleErrors; import static org.egov.common.utils.CommonUtils.havingTenantId; import static org.egov.common.utils.CommonUtils.includeDeleted; @@ -214,27 +215,27 @@ private Tuple, Map> validat return new Tuple<>(validEntities, errorDetailsMap); } - public List search(ProjectFacilitySearchRequest projectFacilitySearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(ProjectFacilitySearchRequest projectFacilitySearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("received request to search project facility"); if (isSearchByIdOnly(projectFacilitySearchRequest.getProjectFacility())) { log.info("searching project facility by id"); List ids = projectFacilitySearchRequest.getProjectFacility().getId(); log.info("fetching project facility with ids: {}", ids); - return projectFacilityRepository.findById(ids, includeDeleted).stream() + List projectfacilities = projectFacilityRepository.findById(ids, includeDeleted).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(projectfacilities).build(); } log.info("searching project facility using criteria"); - return projectFacilityRepository.find(projectFacilitySearchRequest.getProjectFacility(), + return projectFacilityRepository.findWithCount(projectFacilitySearchRequest.getProjectFacility(), limit, offset, tenantId, lastChangedSince, includeDeleted); } - } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java index 660efbd4814..8f8c2555947 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java @@ -5,6 +5,7 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectResource; import org.egov.common.models.project.ProjectResourceBulkRequest; import org.egov.common.models.project.ProjectResourceRequest; @@ -182,27 +183,28 @@ public List delete(ProjectResourceBulkRequest request, boolean } - public List search(ProjectResourceSearchRequest request, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws QueryBuilderException { + public SearchResponse search(ProjectResourceSearchRequest request, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws QueryBuilderException { String idFieldName = getIdFieldName(request.getProjectResource()); if (isSearchByIdOnly(request.getProjectResource(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod((Collections .singletonList(request.getProjectResource()))), request.getProjectResource()); - return projectResourceRepository.findById(ids, includeDeleted, idFieldName).stream() + List projectResources = projectResourceRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(projectResources).build(); } log.info("completed search method for project resource"); - return projectResourceRepository.find(request.getProjectResource(), + return projectResourceRepository.findWithCount(request.getProjectResource(), limit, offset, tenantId, lastChangedSince, includeDeleted); } } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java index 56e2665792a..e27c827ce29 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java @@ -1,7 +1,7 @@ package org.egov.project.service; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import jakarta.validation.Valid; import java.util.Map; import lombok.extern.slf4j.Slf4j; diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java index c600537a74e..d172b96263f 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java @@ -4,6 +4,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.common.models.project.ProjectStaffRequest; @@ -28,9 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.lang.reflect.Type; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Predicate; @@ -224,26 +223,27 @@ private Tuple, Map> validate(List return new Tuple<>(validEntities, errorDetailsMap); } - public List search(ProjectStaffSearchRequest projectStaffSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(ProjectStaffSearchRequest projectStaffSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("received request to search project staff"); if (isSearchByIdOnly(projectStaffSearchRequest.getProjectStaff())) { log.info("searching project staff by id"); List ids = projectStaffSearchRequest.getProjectStaff().getId(); log.info("fetching project staff with ids: {}", ids); - return projectStaffRepository.findById(ids, includeDeleted).stream() + List projectStaffs = projectStaffRepository.findById(ids, includeDeleted).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(projectStaffs).build(); } log.info("searching project staff using criteria"); - return projectStaffRepository.find(projectStaffSearchRequest.getProjectStaff(), + return projectStaffRepository.findWithCount(projectStaffSearchRequest.getProjectStaff(), limit, offset, tenantId, lastChangedSince, includeDeleted); } diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java index 2bd670f589f..6497beb4d53 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import java.util.Map; import java.util.ArrayList; import lombok.extern.slf4j.Slf4j; diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java index db974db9be9..97bdaecc500 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java @@ -4,7 +4,7 @@ import java.util.Map; import java.util.stream.Collectors; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Address; import org.egov.common.models.project.Task; diff --git a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java index 3a0a08d31ea..2ac778f4891 100644 --- a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java @@ -1,26 +1,26 @@ package org.egov.project.util; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; -import digit.models.coremodels.RequestInfoWrapper; import lombok.extern.slf4j.Slf4j; -import net.minidev.json.JSONObject; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.contract.models.RequestInfoWrapper; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.tracer.model.CustomException; +import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - @Component @Slf4j diff --git a/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java b/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java index 4de61e5ab79..be006ad385d 100644 --- a/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java +++ b/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java @@ -5,10 +5,10 @@ import java.util.LinkedList; import java.util.List; -import digit.models.coremodels.mdms.MasterDetail; -import digit.models.coremodels.mdms.MdmsCriteria; -import digit.models.coremodels.mdms.MdmsCriteriaReq; -import digit.models.coremodels.mdms.ModuleDetail; +import org.egov.mdms.model.MasterDetail; +import org.egov.mdms.model.MdmsCriteria; +import org.egov.mdms.model.MdmsCriteriaReq; +import org.egov.mdms.model.ModuleDetail; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java b/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java index 7d750e8d984..8c9b810eecc 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import java.util.Iterator; import java.util.List; import java.util.Map; diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java index 19c8454d63a..c0be5cfcb64 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java @@ -3,10 +3,10 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.mdms.MasterDetail; -import digit.models.coremodels.mdms.MdmsCriteria; -import digit.models.coremodels.mdms.MdmsCriteriaReq; -import digit.models.coremodels.mdms.ModuleDetail; +import org.egov.mdms.model.MasterDetail; +import org.egov.mdms.model.MdmsCriteria; +import org.egov.mdms.model.MdmsCriteriaReq; +import org.egov.mdms.model.ModuleDetail; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; diff --git a/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java b/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java index 266f664312d..9aaba88a427 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java @@ -75,7 +75,7 @@ public void validateCreateProjectRequest(ProjectRequest request) { //Verify MDMS Data // TODO: Uncomment and fix as per HCM once we get clarity // validateRequestMDMSData(request, tenantId, errorMap); - validateAttendanceSessionAgainstMDMS(request,errorMap,tenantId); + if(config.getIsAttendanceFeatureEnabled()) validateAttendanceSessionAgainstMDMS(request,errorMap,tenantId); //Get boundaries in list from all Projects in request body for validation Map> boundariesForValidation = getBoundaryForValidation(request.getProjects()); diff --git a/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java index 7491e024ec3..a33408b813c 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java @@ -1,9 +1,15 @@ package org.egov.project.validator.staff; -import digit.models.coremodels.UserSearchRequest; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.User; +import org.egov.common.contract.user.UserSearchRequest; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; import org.egov.common.models.individual.Individual; @@ -18,12 +24,6 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdToObjMap; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java index e3be161fabb..0a4a68bd917 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java @@ -8,10 +8,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.mdms.MasterDetail; -import digit.models.coremodels.mdms.MdmsCriteria; -import digit.models.coremodels.mdms.MdmsCriteriaReq; -import digit.models.coremodels.mdms.ModuleDetail; import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.Error; @@ -22,6 +18,10 @@ import org.egov.common.service.MdmsService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; +import org.egov.mdms.model.MasterDetail; +import org.egov.mdms.model.MdmsCriteria; +import org.egov.mdms.model.MdmsCriteriaReq; +import org.egov.mdms.model.ModuleDetail; import org.egov.project.config.ProjectConfiguration; import org.egov.tracer.model.CustomException; import org.springframework.core.annotation.Order; diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java index 1b74b7ab1d7..2ec0adc34d3 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java @@ -220,7 +220,7 @@ public ResponseEntity projectFacilityV2SearchPost( @Valid @ModelAttribute URLParams urlParams, @ApiParam(value = "Capture details of Project facility.", required = true) @Valid @RequestBody ProjectFacilitySearchRequest projectFacilitySearchRequest ) throws Exception { - List projectFacilities = projectFacilityService.search( + SearchResponse searchResponse = projectFacilityService.search( projectFacilitySearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -229,7 +229,8 @@ public ResponseEntity projectFacilityV2SearchPost( urlParams.getIncludeDeleted() ); ProjectFacilityBulkResponse response = ProjectFacilityBulkResponse.builder() - .projectFacilities(projectFacilities) + .projectFacilities(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) .responseInfo(ResponseInfoFactory .createResponseInfo(projectFacilitySearchRequest.getRequestInfo(), true)) .build(); @@ -310,7 +311,7 @@ public ResponseEntity projectStaffV1SearchPost( @Valid @ModelAttribute URLParams urlParams, @ApiParam(value = "Capture details of Project staff.", required = true) @Valid @RequestBody ProjectStaffSearchRequest projectStaffSearchRequest ) throws Exception { - List projectStaffList = projectStaffService.search( + SearchResponse searchResponse = projectStaffService.search( projectStaffSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -319,7 +320,8 @@ public ResponseEntity projectStaffV1SearchPost( urlParams.getIncludeDeleted() ); ProjectStaffBulkResponse response = ProjectStaffBulkResponse.builder() - .projectStaff(projectStaffList) + .projectStaff(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) .responseInfo(ResponseInfoFactory .createResponseInfo(projectStaffSearchRequest.getRequestInfo(), true)) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java index 6f71ea7ef93..ef0522cfbf0 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java @@ -7,6 +7,7 @@ import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.project.ProjectResource; import org.egov.common.models.project.ProjectResourceBulkRequest; @@ -75,7 +76,7 @@ public ResponseEntity resourceV1SearchPost( @ApiParam(value = "Search linkage of Project and resource.", required = true) @Valid @RequestBody ProjectResourceSearchRequest projectResourceSearchRequest ) throws QueryBuilderException { - List projectResource = projectResourceService.search( + SearchResponse searchResponse = projectResourceService.search( projectResourceSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -84,7 +85,10 @@ public ResponseEntity resourceV1SearchPost( urlParams.getIncludeDeleted() ); ProjectResourceBulkResponse response = ProjectResourceBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(projectResourceSearchRequest.getRequestInfo(), true)).projectResource(projectResource).build(); + .createResponseInfo(projectResourceSearchRequest.getRequestInfo(), true)) + .projectResource(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) + .build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index 93f601466a9..e27c6d18403 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -180,4 +180,8 @@ project.location.capture.kafka.create.topic=save-location-capture-project-topic project.location.capture.consumer.bulk.create.topic=save-location-capture-project-bulk-topic #---------No resource statuses ------------# -project.task.no.resource.validation.status=ADMINISTRATION_FAILED, BENEFICIARY_REFUSED, CLOSED_HOUSEHOLD, NOT_ADMINISTERED \ No newline at end of file +project.task.no.resource.validation.status=ADMINISTRATION_FAILED, BENEFICIARY_REFUSED, CLOSED_HOUSEHOLD, NOT_ADMINISTERED + +#---------Attendance Feature ------------# +project.attendance.feature.enabled=true + diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java index 93740830a51..fccdb5d0d1d 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.mdms.MdmsCriteriaReq; +import org.egov.mdms.model.MdmsCriteriaReq; import org.apache.commons.io.IOUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java index 805fba5c474..e4675e45bc2 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.mdms.MdmsCriteriaReq; +import org.egov.mdms.model.MdmsCriteriaReq; import org.apache.commons.io.IOUtils; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.core.SearchResponse; diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java index 6eed8465ca5..85fd9f4e71b 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java @@ -1,6 +1,7 @@ package org.egov.project.service; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectFacility; import org.egov.project.helper.ProjectFacilityTestBuilder; import org.egov.project.repository.ProjectFacilityRepository; @@ -46,9 +47,9 @@ void setUp() { @Test @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProjectFacilityFound() throws Exception { - when(projectFacilityRepository.find(any(ProjectFacilitySearch.class), any(Integer.class), + when(projectFacilityRepository.findWithCount(any(ProjectFacilitySearch.class), any(Integer.class), any(Integer.class), any(String.class), eq(null), any(Boolean.class))) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().response(Collections.emptyList()).build()); ProjectFacilitySearch projectFacilitySearch = ProjectFacilitySearch.builder() .id(Collections.singletonList("ID101")).facilityId(Collections.singletonList("some-facility-id")).build(); ProjectFacilitySearchRequest projectFacilitySearchRequest = ProjectFacilitySearchRequest.builder() @@ -77,8 +78,9 @@ void shouldNotRaiseExceptionIfNoProjectFacilityFoundForSearchById() { @Test @DisplayName("should return project facility if search criteria is matched") void shouldReturnProjectFacilityIfSearchCriteriaIsMatched() throws Exception { - when(projectFacilityRepository.find(any(ProjectFacilitySearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectFacilities); + when(projectFacilityRepository.findWithCount(any(ProjectFacilitySearch.class), any(Integer.class), + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder() + .response(projectFacilities).build()); projectFacilities.add(ProjectFacilityTestBuilder.builder().withId().withId().withAuditDetails().build()); ProjectFacilitySearch projectFacilitySearch = ProjectFacilitySearch.builder() .id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-projectId")).build(); @@ -87,7 +89,7 @@ void shouldReturnProjectFacilityIfSearchCriteriaIsMatched() throws Exception { .withCompleteRequestInfo().build()).build(); List projectFacilities = projectFacilityService.search(projectFacilitySearchRequest, - 10, 0, "default", null, false); + 10, 0, "default", null, false).getResponse(); assertEquals(1, projectFacilities.size()); } @@ -104,7 +106,7 @@ void shouldReturnFromCacheIfSearchCriteriaHasIdOnly() throws Exception { when(projectFacilityRepository.findById(anyList(), anyBoolean())).thenReturn(projectFacilities); List projectFacilities = projectFacilityService.search(projectFacilitySearchRequest, - 10, 0, null, null, true); + 10, 0, null, null, true).getResponse(); assertEquals(1, projectFacilities.size()); } diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java index 36aa7100f8d..f14fa8f9a9e 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java @@ -1,6 +1,7 @@ package org.egov.project.service; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectStaff; import org.egov.project.helper.ProjectStaffTestBuilder; import org.egov.project.repository.ProjectStaffRepository; @@ -46,9 +47,9 @@ void setUp() { @Test @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProjectStaffFound() throws Exception { - when(projectStaffRepository.find(any(ProjectStaffSearch.class), any(Integer.class), + when(projectStaffRepository.findWithCount(any(ProjectStaffSearch.class), any(Integer.class), any(Integer.class), any(String.class), eq(null), any(Boolean.class))) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().response(Collections.emptyList()).build()); ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder() .id(Collections.singletonList("ID101")).staffId(Collections.singletonList("some-user-id")).build(); ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder() @@ -75,15 +76,15 @@ void shouldNotRaiseExceptionIfNoProjectStaffFoundForSearchById() { @Test @DisplayName("should return project staff if search criteria is matched") void shouldReturnProjectStaffIfSearchCriteriaIsMatched() throws Exception { - when(projectStaffRepository.find(any(ProjectStaffSearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectStaffs); + when(projectStaffRepository.findWithCount(any(ProjectStaffSearch.class), any(Integer.class), + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().response(projectStaffs).build()); projectStaffs.add(ProjectStaffTestBuilder.builder().withId().withId().withAuditDetails().build()); ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder().id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-projectId")).build(); ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder() .projectStaff(projectStaffSearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); - List projectStaffs = projectStaffService.search(projectStaffSearchRequest, 10, 0, "default", null, false); + List projectStaffs = projectStaffService.search(projectStaffSearchRequest, 10, 0, "default", null, false).getResponse(); assertEquals(1, projectStaffs.size()); } @@ -100,7 +101,7 @@ void shouldReturnFromCacheIfSearchCriteriaHasIdOnly() throws Exception { when(projectStaffRepository.findById(anyList(), anyBoolean())).thenReturn(projectStaffs); List projectStaffs = projectStaffService.search(projectStaffSearchRequest, - 10, 0, null, null, true); + 10, 0, null, null, true).getResponse(); assertEquals(1, projectStaffs.size()); } diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java index e6a97cf70c8..fe6a8e402db 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectFacility; import org.egov.common.models.project.ProjectFacilityBulkRequest; import org.egov.common.models.project.ProjectFacilityBulkResponse; @@ -193,8 +194,9 @@ void shouldAcceptSearchRequestAndReturnProjectFacility() throws Exception { any(Integer.class), any(String.class), any(Long.class), - any(Boolean.class))).thenReturn(Arrays.asList(ProjectFacilityTestBuilder.builder() - .withId().withAuditDetails().build())); + any(Boolean.class))).thenReturn(SearchResponse.builder() + .response(Arrays.asList(ProjectFacilityTestBuilder.builder() + .withId().withAuditDetails().build())).build()); final MvcResult result = mockMvc.perform(post( "/facility/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java index 1e1b5409485..2147e98e460 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkResponse; import org.egov.common.models.project.ProjectStaffRequest; @@ -175,7 +176,7 @@ void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { any(Integer.class), any(String.class), any(Long.class), - any(Boolean.class))).thenReturn(Arrays.asList(ProjectStaffTestBuilder.builder().withId().withAuditDetails().build())); + any(Boolean.class))).thenReturn(SearchResponse.builder().response(Arrays.asList(ProjectStaffTestBuilder.builder().withId().withAuditDetails().build())).build()); final MvcResult result = mockMvc.perform(post( "/staff/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index b9d85ad8269..4bf32a9765a 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -46,12 +46,12 @@ org.egov.common health-services-common - 1.0.18-SNAPSHOT + 1.0.20-dev-SNAPSHOT org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.23-dev-SNAPSHOT compile diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java index d2d43634030..0fee8b9d853 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java @@ -12,6 +12,7 @@ import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearch; import org.egov.common.producer.Producer; @@ -23,6 +24,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; /** @@ -66,7 +68,7 @@ protected HFReferralRepository(Producer producer, NamedParameterJdbcTemplate nam * @param includeDeleted Flag indicating whether to include deleted records. * @return A list of HFReferral entities matching the search criteria. */ - public List find(HFReferralSearch searchObject, Integer limit, Integer offset, String tenantId, + public SearchResponse find(HFReferralSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) { // Initial query to select HFReferral fields from the table. String query = "SELECT hf.id, hf.clientreferenceid, hf.tenantid, hf.projectid, hf.projectfacilityid, hf.symptom, hf.symptomsurveyid, hf.beneficiaryid, hf.referralcode, hf.nationallevelid, hf.createdby, hf.createdtime, hf.lastmodifiedby, hf.lastmodifiedtime, hf.clientcreatedby, hf.clientcreatedtime, hf.clientlastmodifiedby, hf.clientlastmodifiedtime, hf.rowversion, hf.isdeleted, hf.additionaldetails from hf_referral hf"; @@ -96,16 +98,21 @@ public List find(HFReferralSearch searchObject, Integer limit, Integ } // Add ORDER BY, LIMIT, and OFFSET clauses to the query. - query = query + "ORDER BY hf.createdtime DESC LIMIT :limit OFFSET :offset"; + query = query + "ORDER BY hf.createdtime DESC"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query += " LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); // Execute the query and retrieve the list of HFReferral entities. List hfReferralList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); - return hfReferralList; + + return SearchResponse.builder().response(hfReferralList).totalCount(totalCount).build(); } /** @@ -116,7 +123,7 @@ public List find(HFReferralSearch searchObject, Integer limit, Integ * @param columnName The column name to search for IDs. * @return A list of HFReferral entities matching the provided IDs. */ - public List findById(List ids, Boolean includeDeleted, String columnName) { + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { // Find objects in the cache based on the provided IDs. List objFound = findInCache(ids); if (!includeDeleted) { @@ -134,7 +141,7 @@ public List findById(List ids, Boolean includeDeleted, Strin // If no IDs are remaining, return the objects found in the cache. if (ids.isEmpty()) { - return objFound; + return SearchResponse.builder().response(objFound).build(); } } @@ -154,6 +161,6 @@ public List findById(List ids, Boolean includeDeleted, Strin // Add the retrieved entities to the cache. objFound.addAll(hfReferralList); putInCache(objFound); - return objFound; + return SearchResponse.builder().response(objFound).build(); } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java index 5456cd9179c..7994e3d192f 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java index 181aa1b6a55..83971874a2f 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java index 3832d8bd7e3..4b4d961b1f2 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java index c3c287bcff3..bc6aa52dc33 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java @@ -9,6 +9,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; import org.egov.common.models.referralmanagement.hfreferral.HFReferralRequest; @@ -169,12 +170,12 @@ public List update(HFReferralBulkRequest hfReferralRequest, boolean } // Method to search for HFReferrals based on certain criteria - public List search(HFReferralSearchRequest referralSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) { + public SearchResponse search(HFReferralSearchRequest referralSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { log.info("Received request to search referrals"); String idFieldName = getIdFieldName(referralSearchRequest.getHfReferral()); @@ -186,11 +187,12 @@ public List search(HFReferralSearchRequest referralSearchRequest, referralSearchRequest.getHfReferral()); log.info("Fetching referrals with IDs: {}", ids); - return hfReferralRepository.findById(ids, includeDeleted, idFieldName).stream() + List hfReferrals = hfReferralRepository.findById(ids, idFieldName, includeDeleted).getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(hfReferrals).build(); } log.info("Searching referrals using criteria"); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java index 3c09df3edde..7afa7bc0922 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java @@ -1,15 +1,18 @@ package org.egov.referralmanagement.service; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; + + +import com.jayway.jsonpath.JsonPath; import java.util.function.Function; import java.util.stream.Collectors; -import com.jayway.jsonpath.JsonPath; import digit.models.coremodels.mdms.MasterDetail; import digit.models.coremodels.mdms.MdmsCriteria; import digit.models.coremodels.mdms.MdmsCriteriaReq; @@ -22,6 +25,11 @@ import org.egov.common.models.project.ProjectResponse; import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncCriteria; import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; +import org.egov.mdms.model.MasterDetail; +import org.egov.mdms.model.MdmsCriteria; +import org.egov.mdms.model.MdmsCriteriaReq; +import org.egov.mdms.model.ModuleDetail; + import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java index 043c7d6a1b5..3541cb2d4dc 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java @@ -1,7 +1,7 @@ package org.egov.referralmanagement.util; -import digit.models.coremodels.UserSearchRequest; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.user.UserSearchRequest; import org.egov.common.service.UserService; import org.springframework.util.CollectionUtils; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java index 3011cef48ce..d7e81c7e9a4 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java @@ -82,7 +82,8 @@ public Map> validate(HFReferralBulkRequest request) { try { // Query the repository to find existing entities existingReferrals = hfReferralRepository.find(hfReferralSearch, hfReferrals.size(), 0, - hfReferrals.get(0).getTenantId(), null, false); + hfReferrals.get(0).getTenantId(), null, false).getResponse() + ; } catch (Exception e) { // Handle query builder exception log.error("Search failed for HFReferral with error: {}", e.getMessage(), e); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java index e5d62bfee0a..83011aceec9 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java @@ -61,7 +61,7 @@ public Map> validate(HFReferralBulkRequest request) { if (!iMap.isEmpty()) { List hfReferralIds = new ArrayList<>(iMap.keySet()); List existingHfReferrals = hfReferralRepository.findById(hfReferralIds, - false, getIdFieldName(idMethod)); + getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingHfReferrals, idMethod); entitiesWithMismatchedRowVersion.forEach(hfReferral -> { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java index f09a4c578e8..c09a02bebfa 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java @@ -6,6 +6,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; @@ -107,7 +108,7 @@ public ResponseEntity referralV1SearchPost( @ApiParam(value = "HFReferral Search.", required = true) @Valid @RequestBody HFReferralSearchRequest request ) throws Exception { - List hfReferrals = hfReferralService.search( + SearchResponse searchResponse = hfReferralService.search( request, urlParams.getLimit(), urlParams.getOffset(), @@ -115,7 +116,10 @@ public ResponseEntity referralV1SearchPost( urlParams.getLastChangedSince(), urlParams.getIncludeDeleted()); HFReferralBulkResponse response = HFReferralBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).hfReferrals(hfReferrals).build(); + .createResponseInfo(request.getRequestInfo(), true)) + .hfReferrals(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) + .build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java index 32f579e00ff..6f2326d628a 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java @@ -189,6 +189,7 @@ private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigu * @param campaignBoundaryList List of boundary objects related to the campaign. * @param dataFormatter The data formatter for formatting cell values. */ + private void processSheets(PlanConfigurationRequest request, String fileStoreId, Object campaignResponse, Workbook excelWorkbook, List campaignBoundaryList, @@ -311,6 +312,8 @@ private List getBoundaryCodeList(PlanConfigurationRequest planConfigurat * @return A map of attribute names to their corresponding indices or data types. */ + + //TODO: fetch from adminSchema master private Map prepareAttributeVsIndexMap(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, CampaignResponse campaign, PlanConfiguration planConfig, Object mdmsData) { org.egov.processor.web.models.File file = planConfig.getFiles().stream() @@ -367,6 +370,7 @@ private void performRowLevelCalculations(PlanConfigurationRequest planConfigurat campaignIntegrationUtil.updateCampaignBoundary(planConfig, feature, assumptionValueMap, mappedValues, mapOfColumnNameAndIndex, campaignBoundaryList, resultMap); planUtil.create(planConfigurationRequest, feature, resultMap, mappedValues); + } } diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java index bb28c99f0b2..89f0a89511b 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java @@ -144,6 +144,7 @@ public void enrichsheetWithApprovedCensusRecords(Sheet sheet, PlanConfigurationR } } } + log.info("Successfully update file with approved census data."); } } @@ -264,6 +265,7 @@ public void enrichsheetWithApprovedPlanEstimates(Sheet sheet, PlanConfigurationR } } } + log.info("Successfully update file with approved census data."); } } diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index d204ba58903..5cb0c17da56 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.18-SNAPSHOT + 1.0.20-dev-SNAPSHOT org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.23-dev-SNAPSHOT diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java index 813246f8a2b..d05bca6fdd1 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.stock.StockReconciliation; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index e413a3052ac..ea57dbad66d 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.stock.ReferenceIdType; import org.egov.common.models.stock.SenderReceiverType; diff --git a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java index 2951b21e031..e0e3b10b468 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java @@ -21,6 +21,7 @@ import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockReconciliation; +import org.egov.common.models.stock.TransactionType; import org.egov.stock.config.StockConfiguration; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -83,36 +84,46 @@ public Map> validateProjectFacilityMappings(List ent Map> errorDetailsMap, RequestInfo requestInfo) { - + // Get a list of project reference IDs from the entities using reflection List projectIds = getIdList(entities, getMethod(GET_REFERENCE_ID, entities.get(0).getClass())); List facilityIds = null; + // Check the type of entities being processed (either StockReconciliation or Stock) if (entities.get(0) instanceof StockReconciliation) { + + // If the entity is StockReconciliation, extract facility IDs directly facilityIds = getIdList(entities, getMethod(GET_FACILITY_ID, entities.get(0).getClass())); } else if (entities.get(0) instanceof Stock) { + // If the entity is Stock, manually gather facility IDs based on sender/receiver type and transaction type facilityIds = new ArrayList<>(); for (T entity : entities) { Stock stock = (Stock) entity; - if (SenderReceiverType.WAREHOUSE.equals(stock.getSenderType())) { + // Add the sender ID if the sender is a warehouse and the transaction type is DISPATCHED + if (SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) && TransactionType.DISPATCHED.equals(stock.getTransactionType())) { facilityIds.add(stock.getSenderId()); } - if (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType())) { - facilityIds.add(stock.getReceiverId()); - } + + // Add the receiver ID if the receiver is a warehouse and the transaction type is RECEIVED + else if (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) && TransactionType.RECEIVED.equals(stock.getTransactionType())) { + facilityIds.add(stock.getReceiverId()); + } } } + // Calculate the search limit based on the number of project and facility IDs Integer searchLimit = projectIds.size() * facilityIds.size(); + // Build a request object to search for project-facility mappings ProjectFacilitySearchRequest projectFacilitySearchRequest = ProjectFacilitySearchRequest.builder() .projectFacility(ProjectFacilitySearch.builder().projectId(projectIds).facilityId(facilityIds).build()) .requestInfo(requestInfo) .build(); try { + // Call an external service to fetch project-facility mappings using the constructed request ProjectFacilityBulkResponse response = serviceRequestClient.fetchResult( new StringBuilder(stockConfiguration.getProjectFacilityServiceHost() + stockConfiguration.getProjectFacilityServiceSearchUrl() @@ -121,11 +132,13 @@ public Map> validateProjectFacilityMappings(List ent projectFacilitySearchRequest, ProjectFacilityBulkResponse.class); + // Group the response by project ID and collect facility IDs associated with each project return response.getProjectFacilities().stream() .collect(Collectors.groupingBy(projectFacility -> projectFacility.getProjectId(), Collectors.mapping(projectFacility -> projectFacility.getFacilityId(), Collectors.toList()))); } catch (Exception e) { + // If an exception occurs, log the error and add network error details to each entity in the errorDetailsMap log.error("error while fetching project facility list: {}", ExceptionUtils.getStackTrace(e)); entities.forEach(b -> { Error error = getErrorForEntityWithNetworkError(); diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java index 6c6801a5922..69340c5efca 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java @@ -10,6 +10,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; import org.egov.common.models.stock.StockReconciliationRequest; @@ -182,26 +183,27 @@ public List delete(StockReconciliationBulkRequest request, return validEntities; } - public List search(StockReconciliationSearchRequest request, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(StockReconciliationSearchRequest request, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("starting search method for stock reconciliation"); String idFieldName = getIdFieldName(request.getStockReconciliation()); if (isSearchByIdOnly(request.getStockReconciliation(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(request.getStockReconciliation())), request.getStockReconciliation()); - return stockRepository.findById(ids, includeDeleted, idFieldName).stream() + List stockReconciliations = stockRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(stockReconciliations).build(); } log.info("completed search method for stock reconciliation"); - return stockRepository.find(request.getStockReconciliation(), + return stockRepository.findWithCount(request.getStockReconciliation(), limit, offset, tenantId, lastChangedSince, includeDeleted); } } diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java index 6a26da44ced..c6b60278be7 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java @@ -10,6 +10,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.common.models.stock.StockRequest; @@ -177,27 +178,28 @@ public List delete(StockBulkRequest request, boolean isBulk) { return validEntities; } - public List search(StockSearchRequest stockSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(StockSearchRequest stockSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("starting search method for stock"); String idFieldName = getIdFieldName(stockSearchRequest.getStock()); if (isSearchByIdOnly(stockSearchRequest.getStock(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(stockSearchRequest.getStock())), stockSearchRequest.getStock()); - return stockRepository.findById(ids, includeDeleted, idFieldName).stream() + List stocks = stockRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(stocks).build(); } log.info("completed search method for stock"); - return stockRepository.find(stockSearchRequest.getStock(), + return stockRepository.findWithCount(stockSearchRequest.getStock(), limit, offset, tenantId, lastChangedSince, includeDeleted); } } diff --git a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java index d71f92cda2d..5c436e37811 100644 --- a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java +++ b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java @@ -6,13 +6,14 @@ import java.util.Map; import java.util.stream.Collectors; -import digit.models.coremodels.UserSearchRequest; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.user.UserSearchRequest; import org.egov.common.ds.Tuple; import org.egov.common.models.Error; import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockReconciliation; +import org.egov.common.models.stock.TransactionType; import org.egov.common.service.UserService; import org.egov.stock.service.FacilityService; import org.egov.tracer.model.CustomException; @@ -265,20 +266,44 @@ private static void enrichErrorForStock(List validEntities, for (Stock stock : validEntities) { + // Get the sender and receiver IDs from the stock object String senderId = stock.getSenderId(); String receiverId = stock.getReceiverId(); + // Get the list of facility IDs mapped to the reference ID of the stock List facilityIds = ProjectFacilityMappingOfIds.get(stock.getReferenceId()); - if (!CollectionUtils.isEmpty(facilityIds)) { - if (SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) && !facilityIds.contains(senderId)) { - populateErrorForStock(stock, senderId, errorDetailsMap); - } + // Check if the stock involves a warehouse and a valid transaction type (DISPATCHED or RECEIVED) + if ((SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) && TransactionType.DISPATCHED.equals(stock.getTransactionType())) + || (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) && TransactionType.RECEIVED.equals(stock.getTransactionType()))) { + + // If facilityIds are not empty, validate the sender and receiver IDs based on TransactionType + if (!CollectionUtils.isEmpty(facilityIds)) { + + // Check if the sender is a warehouse and the transaction is DISPATCHED + // Validate that the sender ID is in the facility IDs, otherwise log an error + if (SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) + && !facilityIds.contains(senderId) + && TransactionType.DISPATCHED.equals(stock.getTransactionType())) { + + // Log an error for the invalid sender + populateErrorForStock(stock, senderId, errorDetailsMap); + } - if (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) && !facilityIds.contains(receiverId)) - populateErrorForStock(stock, receiverId, errorDetailsMap); - } else { - populateErrorForStock(stock, senderId + " and " + receiverId, errorDetailsMap); + // Check if the receiver is a warehouse and the transaction is RECEIVED + // Validate that the receiver ID is in the facility IDs, otherwise log an error + if (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) + && !facilityIds.contains(receiverId) + && TransactionType.RECEIVED.equals(stock.getTransactionType())) { + + // Log an error for the invalid receiver + populateErrorForStock(stock, receiverId, errorDetailsMap); + } + } else { + + // If facilityIds are empty, log an error for both sender and receiver + populateErrorForStock(stock, senderId + " and " + receiverId, errorDetailsMap); + } } } } diff --git a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java index 913213dd191..7033f50a14a 100644 --- a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java +++ b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java @@ -8,6 +8,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; @@ -80,7 +81,7 @@ public ResponseEntity stockV1SearchPost( @ApiParam(value = "Capture details of Stock Transfer.", required = true) @Valid @RequestBody StockSearchRequest stockSearchRequest ) throws Exception { - List stock = stockService.search( + SearchResponse searchResponse = stockService.search( stockSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -89,7 +90,7 @@ public ResponseEntity stockV1SearchPost( urlParams.getIncludeDeleted() ); StockBulkResponse response = StockBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(stockSearchRequest.getRequestInfo(), true)).stock(stock).build(); + .createResponseInfo(stockSearchRequest.getRequestInfo(), true)).stock(searchResponse.getResponse()).totalCount(searchResponse.getTotalCount()).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java index e612c3b692f..41fc33437e9 100644 --- a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java +++ b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java @@ -7,6 +7,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; @@ -77,7 +78,7 @@ public ResponseEntity stockReconciliationV1Sear @ApiParam(value = "Capture details of Stock Reconciliation.", required = true) @Valid @RequestBody StockReconciliationSearchRequest stockReconciliationSearchRequest ) throws Exception { - List stock = stockReconciliationService.search( + SearchResponse searchResponse = stockReconciliationService.search( stockReconciliationSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -86,7 +87,10 @@ public ResponseEntity stockReconciliationV1Sear urlParams.getIncludeDeleted() ); StockReconciliationBulkResponse response = StockReconciliationBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(stockReconciliationSearchRequest.getRequestInfo(), true)).stockReconciliation(stock).build(); + .createResponseInfo(stockReconciliationSearchRequest.getRequestInfo(), true)) + .stockReconciliation(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) + .build(); return ResponseEntity.status(HttpStatus.OK).body(response); } From 717aeac28f2761e856ac4af8d71cdb9fe8f2984b Mon Sep 17 00:00:00 2001 From: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:22:21 +0530 Subject: [PATCH 17/29] Moving PlanValidator and PlanEnricher to respective folders. (#1280) --- .../plan-service/src/main/java/digit/service/PlanService.java | 4 ++-- .../java/digit/service/{ => enrichment}/PlanEnricher.java | 2 +- .../java/digit/service/{ => validator}/PlanValidator.java | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) rename health-services/plan-service/src/main/java/digit/service/{ => enrichment}/PlanEnricher.java (99%) rename health-services/plan-service/src/main/java/digit/service/{ => validator}/PlanValidator.java (99%) diff --git a/health-services/plan-service/src/main/java/digit/service/PlanService.java b/health-services/plan-service/src/main/java/digit/service/PlanService.java index 4acaf58218b..dad7e8b7d83 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanService.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanService.java @@ -1,13 +1,13 @@ package digit.service; import digit.repository.PlanRepository; +import digit.service.enrichment.PlanEnricher; +import digit.service.validator.PlanValidator; import digit.service.workflow.WorkflowService; import digit.web.models.*; -import org.egov.common.contract.response.ResponseInfo; import org.egov.common.utils.ResponseInfoUtil; import org.springframework.stereotype.Service; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; diff --git a/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java b/health-services/plan-service/src/main/java/digit/service/enrichment/PlanEnricher.java similarity index 99% rename from health-services/plan-service/src/main/java/digit/service/PlanEnricher.java rename to health-services/plan-service/src/main/java/digit/service/enrichment/PlanEnricher.java index b01c78ea82a..17364bfdb6d 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java +++ b/health-services/plan-service/src/main/java/digit/service/enrichment/PlanEnricher.java @@ -1,4 +1,4 @@ -package digit.service; +package digit.service.enrichment; import digit.web.models.Plan; import digit.web.models.PlanRequest; diff --git a/health-services/plan-service/src/main/java/digit/service/PlanValidator.java b/health-services/plan-service/src/main/java/digit/service/validator/PlanValidator.java similarity index 99% rename from health-services/plan-service/src/main/java/digit/service/PlanValidator.java rename to health-services/plan-service/src/main/java/digit/service/validator/PlanValidator.java index aa1656c00b3..1fd98c823b7 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanValidator.java +++ b/health-services/plan-service/src/main/java/digit/service/validator/PlanValidator.java @@ -1,9 +1,11 @@ -package digit.service; +package digit.service.validator; import com.jayway.jsonpath.JsonPath; import digit.config.Configuration; import digit.repository.PlanConfigurationRepository; import digit.repository.PlanRepository; +import digit.service.PlanEmployeeService; +import digit.service.enrichment.PlanEnricher; import digit.util.BoundaryUtil; import digit.util.CampaignUtil; import digit.util.CommonUtil; From 9dbb1d73f71a2e883717efd83e4d0866a76f36bd Mon Sep 17 00:00:00 2001 From: Shashwat Mishra <71879793+shashwat-egov@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:21:25 +0530 Subject: [PATCH 18/29] fixed import issues (#1281) Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> --- .../egov/servicerequest/web/models/AttributeDefinition.java | 4 +--- .../egov/referralmanagement/service/MasterDataService.java | 4 ---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java index 62616b6b677..649421350a1 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java @@ -62,9 +62,7 @@ public enum DataTypeEnum { MULTIVALUELIST("MultiValueList"), - FILE("File"), - - BOOLEAN("Boolean"); + FILE("File"); private String value; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java index 7afa7bc0922..c812f7c5021 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java @@ -13,10 +13,6 @@ import java.util.function.Function; import java.util.stream.Collectors; -import digit.models.coremodels.mdms.MasterDetail; -import digit.models.coremodels.mdms.MdmsCriteria; -import digit.models.coremodels.mdms.MdmsCriteriaReq; -import digit.models.coremodels.mdms.ModuleDetail; import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; From 73dfdb9053d3e4385949a555dd4a556d5ac997bb Mon Sep 17 00:00:00 2001 From: Tanishi Goyal Date: Wed, 18 Dec 2024 11:14:10 +0530 Subject: [PATCH 19/29] Adding a column for facility name --- .../processor/config/ServiceConstants.java | 4 + .../egov/processor/service/ExcelParser.java | 6 +- .../egov/processor/util/EnrichmentUtil.java | 4 +- .../util/OutputEstimationGenerationUtil.java | 93 ++++++++++++++++++- .../org/egov/processor/util/ParsingUtil.java | 56 ++++++++++- 5 files changed, 154 insertions(+), 9 deletions(-) diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java index 7200f29cecc..dd3a9f71c5c 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -39,6 +39,9 @@ public class ServiceConstants { public static final String FILE_NOT_FOUND_CODE = "FILE_NOT_FOUND"; public static final String FILE_NOT_FOUND_MESSAGE = "No file with the specified templateIdentifier found - "; + public static final String PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE = "PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT"; + public static final String PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE = "Key is not present in json object - "; + public static final String UNABLE_TO_CREATE_ADDITIONAL_DETAILS_CODE = "UNABLE_TO_CREATE_ADDITIONAL_DETAILS"; public static final String UNABLE_TO_CREATE_ADDITIONAL_DETAILS_MESSAGE = "Unable to create additional details for facility creation."; @@ -116,6 +119,7 @@ public class ServiceConstants { public static final String SOURCE_KEY = "source"; public static final String MICROPLAN_SOURCE_KEY = "microplan"; public static final String MICROPLAN_ID_KEY = "microplanId"; + public static final String FACILITY_NAME = "facilityName"; //Census additional field constants public static final String UPLOADED_KEY = "UPLOADED_"; diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java index 459acda94ed..2faa00b43f5 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java @@ -127,7 +127,7 @@ private void processExcelFile(PlanConfigurationRequest planConfigurationRequest, processSheets(planConfigurationRequest, fileStoreId, campaignResponse, workbook, campaignBoundaryList, dataFormatter); uploadFileAndIntegrateCampaign(planConfigurationRequest, campaignResponse, - workbook, campaignBoundaryList, campaignResourcesList); + workbook, campaignBoundaryList, campaignResourcesList, fileStoreId); } catch (FileNotFoundException e) { log.error("File not found: {}", e.getMessage()); throw new CustomException("FileNotFound", "The specified file was not found."); @@ -152,7 +152,7 @@ private void processExcelFile(PlanConfigurationRequest planConfigurationRequest, */ private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigurationRequest, Object campaignResponse, Workbook workbook, - List campaignBoundaryList, List campaignResourcesList) { + List campaignBoundaryList, List campaignResourcesList, String filestoreId) { File fileToUpload = null; try { PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); @@ -169,6 +169,8 @@ private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigu outputEstimationGenerationUtil.processOutputFile(workbook, planConfigurationRequest); + // Adding facility information for each boundary code + outputEstimationGenerationUtil.addAssignedFacility(workbook, planConfigurationRequest, filestoreId); //update processed output file into plan configuration file object fileToUpload = convertWorkbookToXls(workbook); diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java index d0cd40201ff..e543dd062a3 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java @@ -223,10 +223,10 @@ public void enrichsheetWithApprovedPlanEstimates(Sheet sheet, PlanConfigurationR Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); - //Getting census records for the list of boundaryCodes + //Getting plan records for the list of boundaryCodes List planList = getPlanRecordsForEnrichment(planConfigurationRequest, boundaryCodes); - // Create a map from boundaryCode to Census for quick lookups + // Create a map from boundaryCode to Plan for quick lookups Map planMap = planList.stream() .collect(Collectors.toMap(Plan::getLocality, plan -> plan)); diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java index b3931574ca5..9f8a2b36562 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java @@ -1,20 +1,32 @@ package org.egov.processor.util; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.*; import org.egov.processor.web.models.LocaleResponse; import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.ResourceMapping; +import org.egov.processor.web.models.census.Census; +import org.springframework.stereotype.Component; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.processor.config.ServiceConstants.FACILITY_NAME; + +@Component public class OutputEstimationGenerationUtil { private LocaleUtil localeUtil; private ParsingUtil parsingUtil; - public OutputEstimationGenerationUtil(LocaleUtil localeUtil, ParsingUtil parsingUtil) { + private EnrichmentUtil enrichmentUtil; + + public OutputEstimationGenerationUtil(LocaleUtil localeUtil, ParsingUtil parsingUtil, EnrichmentUtil enrichmentUtil) { this.localeUtil = localeUtil; this.parsingUtil = parsingUtil; + this.enrichmentUtil = enrichmentUtil; } public void processOutputFile(Workbook workbook, PlanConfigurationRequest request) { @@ -38,4 +50,77 @@ public void processSheetForHeaderLocalization(Sheet sheet, LocaleResponse locale } } + + /** + * For each boundary code in the sheet being processed, adds the name of the facility mapped to that boundary code. + * + * @param workbook the workbook. + * @param request the plan configuration request. + * @param fileStoreId the associated file store ID. + */ + public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest request, String fileStoreId) { + LocaleResponse localeResponse = localeUtil.searchLocale(request); + +// String assignedFacilityColHeader = localeUtil.localeSearch(localeResponse.getMessages(), "FACILITY_ASSIGNED"); + + String assignedFacilityColHeader = "Facility assigned"; + + for (int i = 0; i < workbook.getNumberOfSheets(); i++) { + Sheet sheet = workbook.getSheetAt(i); + if (!parsingUtil.isSheetAllowedToProcess(request, sheet.getSheetName(), localeResponse)) { + + // Get column index of assigned facility name in the sheet being processed + Integer indexOfFacility = sheet.getRow(0).getLastCellNum() + 1; + + // Create a new column for assigned facility name + Cell cell = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); + cell.setCellValue(assignedFacilityColHeader); + + // Creating a map of MappedTo and MappedFrom values from resource mapping + Map mappedValues = request.getPlanConfiguration().getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap( + ResourceMapping::getMappedTo, + ResourceMapping::getMappedFrom, + (existing, replacement) -> existing, + LinkedHashMap::new + )); + + // Get column index of boundary code in the sheet being processed + Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, sheet, mappedValues); + + // Get a list of boundary codes + List boundaryCodes = enrichmentUtil.getBoundaryCodesFromTheSheet(sheet, request, fileStoreId); + + //Getting census records for the list of boundaryCodes + List censusList = enrichmentUtil.getCensusRecordsForEnrichment(request, boundaryCodes); + + // Create a map of boundary code to facility assigned for the boundary + Map boundaryCodeToFacility = censusList.stream() + .collect(Collectors.toMap(Census::getBoundaryCode, census -> (String) parsingUtil.extractFieldsFromJsonObject(census.getAdditionalDetails(), FACILITY_NAME))); + + // for each boundary code in the sheet add the name of the facility assigned to it. + for (Row row : sheet) { + + // Skip the header row and empty rows + if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { + continue; + } + + // Get the boundaryCode in the current row + Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); + String boundaryCode = boundaryCodeCell.getStringCellValue(); + + String facility = boundaryCodeToFacility.get(boundaryCode); + + Cell facilityCell = row.getCell(indexOfFacility); + if (facilityCell == null) { + facilityCell = row.createCell(indexOfFacility, CellType.STRING); + } + facilityCell.setCellValue(facility); + } + } + } + + } } diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java index bfcf1dd8c9b..21c1e2b99f8 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java @@ -17,6 +17,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.*; @@ -38,11 +39,14 @@ public class ParsingUtil { private MdmsUtil mdmsUtil; - public ParsingUtil(PlanConfigurationUtil planConfigurationUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil, MdmsUtil mdmsUtil) { + private ObjectMapper objectMapper; + + public ParsingUtil(PlanConfigurationUtil planConfigurationUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil, MdmsUtil mdmsUtil, ObjectMapper objectMapper) { this.planConfigurationUtil = planConfigurationUtil; this.filestoreUtil = filestoreUtil; this.calculationUtil = calculationUtil; this.mdmsUtil = mdmsUtil; + this.objectMapper = objectMapper; } public List fetchAttributeNamesFromJson(JsonNode jsonNode) @@ -346,6 +350,23 @@ public Integer getIndexOfBoundaryCode(Integer indexValue, List mappedValues) { + + DataFormatter dataFormatter = new DataFormatter(); + + // Assuming the first row contains column headers + Row headerRow = sheet.getRow(0); + for (int i = 0; i < headerRow.getLastCellNum(); i++) { + Cell cell = headerRow.getCell(i); + String columnHeader = dataFormatter.formatCellValue(cell); + if(columnHeader.equals(mappedValues.get(ServiceConstants.BOUNDARY_CODE))) { + indexValue = i; + break; + } + } + return indexValue; + } + /** * Sorts the column names and indices based on the provided map of column names and indices. * @@ -418,4 +439,37 @@ public boolean isSheetAllowedToProcess(PlanConfigurationRequest planConfiguratio } + /** + * Extracts provided field from the additional details object + * + * @param additionalDetails the additionalDetails object from PlanConfigurationRequest + * @param fieldToExtract the name of the field to be extracted from the additional details + * @return the value of the specified field as a string + * @throws CustomException if the field does not exist + */ + public Object extractFieldsFromJsonObject(Object additionalDetails, String fieldToExtract) { + try { + String jsonString = objectMapper.writeValueAsString(additionalDetails); + JsonNode rootNode = objectMapper.readTree(jsonString); + + JsonNode node = rootNode.get(fieldToExtract); + if (node != null && !node.isNull()) { + + // Check for different types of JSON nodes + if (node.isDouble() || node.isFloat()) { + return BigDecimal.valueOf(node.asDouble()); // Convert Double to BigDecimal + } else if (node.isLong() || node.isInt()) { + return BigDecimal.valueOf(node.asLong()); // Convert Long to BigDecimal + } else if (node.isBoolean()) { + return node.asBoolean(); + } else if (node.isTextual()) { + return node.asText(); + } + } + return null; + } catch (Exception e) { + log.error(e.getMessage() + fieldToExtract); + throw new CustomException(PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE, PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE + fieldToExtract); + } + } } From d0f135e2210dfeca394b923630052cdde62d5484 Mon Sep 17 00:00:00 2001 From: Tanishi Goyal Date: Wed, 18 Dec 2024 16:32:50 +0530 Subject: [PATCH 20/29] Adding a column for facility name --- .../org/egov/processor/util/OutputEstimationGenerationUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java index 9f8a2b36562..247a967c7d5 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java @@ -67,7 +67,7 @@ public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest requ for (int i = 0; i < workbook.getNumberOfSheets(); i++) { Sheet sheet = workbook.getSheetAt(i); - if (!parsingUtil.isSheetAllowedToProcess(request, sheet.getSheetName(), localeResponse)) { + if (parsingUtil.isSheetAllowedToProcess(request, sheet.getSheetName(), localeResponse)) { // Get column index of assigned facility name in the sheet being processed Integer indexOfFacility = sheet.getRow(0).getLastCellNum() + 1; From d8937bddafb215d922f88a361c3c88a8e7d646c0 Mon Sep 17 00:00:00 2001 From: Tanishi Goyal Date: Thu, 19 Dec 2024 10:51:41 +0530 Subject: [PATCH 21/29] Adding a column for facility name --- .../java/org/egov/processor/config/ServiceConstants.java | 1 + .../egov/processor/util/OutputEstimationGenerationUtil.java | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java index dd3a9f71c5c..5d4af773b33 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -120,6 +120,7 @@ public class ServiceConstants { public static final String MICROPLAN_SOURCE_KEY = "microplan"; public static final String MICROPLAN_ID_KEY = "microplanId"; public static final String FACILITY_NAME = "facilityName"; + public static final String FACILITY_ASSIGNED_CODE = "FACILITY_ASSIGNED"; //Census additional field constants public static final String UPLOADED_KEY = "UPLOADED_"; diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java index 247a967c7d5..c68a60b195b 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java @@ -12,6 +12,7 @@ import java.util.Map; import java.util.stream.Collectors; +import static org.egov.processor.config.ServiceConstants.FACILITY_ASSIGNED_CODE; import static org.egov.processor.config.ServiceConstants.FACILITY_NAME; @Component @@ -61,9 +62,9 @@ public void processSheetForHeaderLocalization(Sheet sheet, LocaleResponse locale public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest request, String fileStoreId) { LocaleResponse localeResponse = localeUtil.searchLocale(request); -// String assignedFacilityColHeader = localeUtil.localeSearch(localeResponse.getMessages(), "FACILITY_ASSIGNED"); + String assignedFacilityColHeader = localeUtil.localeSearch(localeResponse.getMessages(), FACILITY_ASSIGNED_CODE); - String assignedFacilityColHeader = "Facility assigned"; + assignedFacilityColHeader = assignedFacilityColHeader != null ? assignedFacilityColHeader : FACILITY_ASSIGNED_CODE; for (int i = 0; i < workbook.getNumberOfSheets(); i++) { Sheet sheet = workbook.getSheetAt(i); From c9d1f61d790e5b83c98aed64dbe7908f1bf1bd19 Mon Sep 17 00:00:00 2001 From: Tanishi Goyal Date: Thu, 19 Dec 2024 10:58:44 +0530 Subject: [PATCH 22/29] Adding a column for facility name --- .../src/main/java/org/egov/processor/util/ParsingUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java index 6ac106271d9..066f173e1c7 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java @@ -359,7 +359,7 @@ public Integer getIndexOfBoundaryCode(Integer indexValue, Sheet sheet, Map Date: Thu, 19 Dec 2024 11:42:32 +0530 Subject: [PATCH 23/29] Adding a column for facility name --- .../java/org/egov/processor/config/ServiceConstants.java | 2 +- .../egov/processor/util/OutputEstimationGenerationUtil.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java index 5d4af773b33..bbb2c816eb1 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -120,7 +120,7 @@ public class ServiceConstants { public static final String MICROPLAN_SOURCE_KEY = "microplan"; public static final String MICROPLAN_ID_KEY = "microplanId"; public static final String FACILITY_NAME = "facilityName"; - public static final String FACILITY_ASSIGNED_CODE = "FACILITY_ASSIGNED"; + public static final String HCM_MICROPLAN_SERVING_FACILITY = "HCM_MICROPLAN_SERVING_FACILITY"; //Census additional field constants public static final String UPLOADED_KEY = "UPLOADED_"; diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java index 011a24177c9..353110f2e4f 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java @@ -14,8 +14,8 @@ import java.util.stream.Collectors; import org.egov.tracer.model.CustomException; -import static org.egov.processor.config.ServiceConstants.FACILITY_ASSIGNED_CODE; import static org.egov.processor.config.ServiceConstants.FACILITY_NAME; +import static org.egov.processor.config.ServiceConstants.HCM_MICROPLAN_SERVING_FACILITY; @Component public class OutputEstimationGenerationUtil { @@ -86,9 +86,9 @@ public void processSheetForHeaderLocalization(Sheet sheet, Map l public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest request, String fileStoreId) { LocaleResponse localeResponse = localeUtil.searchLocale(request); - String assignedFacilityColHeader = localeUtil.localeSearch(localeResponse.getMessages(), FACILITY_ASSIGNED_CODE); + String assignedFacilityColHeader = localeUtil.localeSearch(localeResponse.getMessages(), HCM_MICROPLAN_SERVING_FACILITY); - assignedFacilityColHeader = assignedFacilityColHeader != null ? assignedFacilityColHeader : FACILITY_ASSIGNED_CODE; + assignedFacilityColHeader = assignedFacilityColHeader != null ? assignedFacilityColHeader : HCM_MICROPLAN_SERVING_FACILITY; for (int i = 0; i < workbook.getNumberOfSheets(); i++) { Sheet sheet = workbook.getSheetAt(i); From 1217dd758e05d501daee83dbb360eb68480333a8 Mon Sep 17 00:00:00 2001 From: Tanishi Goyal Date: Fri, 20 Dec 2024 12:00:51 +0530 Subject: [PATCH 24/29] Adding styling to the column header --- .../util/OutputEstimationGenerationUtil.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java index 9474c4627f5..09081827a06 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java @@ -112,11 +112,12 @@ public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest requ if (parsingUtil.isSheetAllowedToProcess(request, sheet.getSheetName(), localeResponse)) { // Get column index of assigned facility name in the sheet being processed - Integer indexOfFacility = sheet.getRow(0).getLastCellNum() + 1; + Integer indexOfFacility = (int) sheet.getRow(0).getLastCellNum(); // Create a new column for assigned facility name - Cell cell = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); - cell.setCellValue(assignedFacilityColHeader); + Cell facilityCell = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); + excelStylingUtil.styleCell(facilityCell); + facilityCell.setCellValue(assignedFacilityColHeader); // Get column index of boundary code in the sheet being processed from map of col name and index Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); @@ -144,14 +145,13 @@ public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest requ Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); String boundaryCode = boundaryCodeCell.getStringCellValue(); - Cell facilityCell = row.getCell(indexOfFacility); - if (facilityCell == null) { - facilityCell = row.createCell(indexOfFacility, CellType.STRING); + Cell facilityName = row.getCell(indexOfFacility); + if (facilityName == null) { + facilityName = row.createCell(indexOfFacility, CellType.STRING); } // Setting facility name for the boundary from boundaryCodeToFacility map - excelStylingUtil.styleCell(facilityCell); - facilityCell.setCellValue(boundaryCodeToFacility.get(boundaryCode)); + facilityName.setCellValue(boundaryCodeToFacility.get(boundaryCode)); } } } From a4f3c28386a4022f3872ab8fa9a7d35c736c0724 Mon Sep 17 00:00:00 2001 From: Tanishi Goyal Date: Fri, 20 Dec 2024 12:01:48 +0530 Subject: [PATCH 25/29] Adding styling to the column header --- .../util/OutputEstimationGenerationUtil.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java index 09081827a06..00195df3b6d 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java @@ -115,9 +115,9 @@ public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest requ Integer indexOfFacility = (int) sheet.getRow(0).getLastCellNum(); // Create a new column for assigned facility name - Cell facilityCell = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); - excelStylingUtil.styleCell(facilityCell); - facilityCell.setCellValue(assignedFacilityColHeader); + Cell facilityColHeader = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); + excelStylingUtil.styleCell(facilityColHeader); + facilityColHeader.setCellValue(assignedFacilityColHeader); // Get column index of boundary code in the sheet being processed from map of col name and index Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); @@ -145,13 +145,13 @@ public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest requ Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); String boundaryCode = boundaryCodeCell.getStringCellValue(); - Cell facilityName = row.getCell(indexOfFacility); - if (facilityName == null) { - facilityName = row.createCell(indexOfFacility, CellType.STRING); + Cell facilityCell = row.getCell(indexOfFacility); + if (facilityCell == null) { + facilityCell = row.createCell(indexOfFacility, CellType.STRING); } // Setting facility name for the boundary from boundaryCodeToFacility map - facilityName.setCellValue(boundaryCodeToFacility.get(boundaryCode)); + facilityCell.setCellValue(boundaryCodeToFacility.get(boundaryCode)); } } } From 5cd6e2f5ae2f1c24dc43a1ecaec0f9873fbf0a60 Mon Sep 17 00:00:00 2001 From: Tanishi Goyal Date: Fri, 27 Dec 2024 14:49:47 +0530 Subject: [PATCH 26/29] Adding function comments --- .../util/OutputEstimationGenerationUtil.java | 192 ++++++++++++++---- 1 file changed, 152 insertions(+), 40 deletions(-) diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java index 00195df3b6d..ae72a60c007 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java @@ -8,6 +8,7 @@ import org.egov.processor.web.models.census.Census; import org.springframework.stereotype.Component; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -84,12 +85,90 @@ public void processSheetForHeaderLocalization(Sheet sheet, Map l } +// /** +// * For each boundary code in the sheet being processed, adds the name of the facility mapped to that boundary code. +// * +// * @param workbook the workbook. +// * @param request the plan configuration request. +// * @param fileStoreId the associated file store ID. +// */ +// public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest request, String fileStoreId) { +// LocaleResponse localeResponse = localeUtil.searchLocale(request); +// +// String assignedFacilityColHeader = localeUtil.localeSearch(localeResponse.getMessages(), HCM_MICROPLAN_SERVING_FACILITY); +// assignedFacilityColHeader = assignedFacilityColHeader != null ? assignedFacilityColHeader : HCM_MICROPLAN_SERVING_FACILITY; +// +// // Creating a map of MappedTo and MappedFrom values from resource mapping +// Map mappedValues = request.getPlanConfiguration().getResourceMapping().stream() +// .filter(f -> f.getFilestoreId().equals(fileStoreId)) +// .collect(Collectors.toMap( +// ResourceMapping::getMappedTo, +// ResourceMapping::getMappedFrom, +// (existing, replacement) -> existing, +// LinkedHashMap::new +// )); +// +// for (int i = 0; i < workbook.getNumberOfSheets(); i++) { +// Sheet sheet = workbook.getSheetAt(i); +// if (parsingUtil.isSheetAllowedToProcess(request, sheet.getSheetName(), localeResponse)) { +// +// // Get column index of assigned facility name in the sheet being processed +// Integer indexOfFacility = (int) sheet.getRow(0).getLastCellNum(); +// +// // Create a new column for assigned facility name +// Cell facilityColHeader = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); +// excelStylingUtil.styleCell(facilityColHeader); +// facilityColHeader.setCellValue(assignedFacilityColHeader); +// +// // Get column index of boundary code in the sheet being processed from map of col name and index +// Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); +// Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, +// parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); +// +// // Get a list of boundary codes +// List boundaryCodes = enrichmentUtil.getBoundaryCodesFromTheSheet(sheet, request, fileStoreId); +// +// //Getting census records for the list of boundaryCodes +// List censusList = enrichmentUtil.getCensusRecordsForEnrichment(request, boundaryCodes); +// +// // Create a map of boundary code to facility assigned for the boundary +// Map boundaryCodeToFacility = censusList.stream() +// .collect(Collectors.toMap(Census::getBoundaryCode, census -> (String) parsingUtil.extractFieldsFromJsonObject(census.getAdditionalDetails(), FACILITY_NAME))); +// +// // for each boundary code in the sheet add the name of the facility assigned to it. +// for (Row row : sheet) { +// // Skip the header row and empty rows +// if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { +// continue; +// } +// +// // Get the boundaryCode in the current row +// Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); +// String boundaryCode = boundaryCodeCell.getStringCellValue(); +// +// Cell facilityCell = row.getCell(indexOfFacility); +// if (facilityCell == null) { +// facilityCell = row.createCell(indexOfFacility, CellType.STRING); +// } +// +// // Setting facility name for the boundary from boundaryCodeToFacility map +// facilityCell.setCellValue(boundaryCodeToFacility.get(boundaryCode)); +// } +// } +// } +// +// } +// +// + /** - * For each boundary code in the sheet being processed, adds the name of the facility mapped to that boundary code. + * This is the main method responsible for adding an assigned facility name column to each sheet in the workbook. + * It iterates through all the sheets, verifies if they are eligible for processing, retrieves required mappings + * and boundary codes, and populates the new column with facility names based on these mappings. * - * @param workbook the workbook. - * @param request the plan configuration request. - * @param fileStoreId the associated file store ID. + * @param workbook the workbook containing the sheets to be processed. + * @param request the plan configuration request containing the resource mapping and other configurations. + * @param fileStoreId the associated file store ID used to filter resource mappings. */ public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest request, String fileStoreId) { LocaleResponse localeResponse = localeUtil.searchLocale(request); @@ -107,54 +186,87 @@ public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest requ LinkedHashMap::new )); + // Get the map of boundary code to the facility assigned to that boundary. + Map boundaryCodeToFacility = getBoundaryCodeToFacilityMap(workbook, request, fileStoreId); + for (int i = 0; i < workbook.getNumberOfSheets(); i++) { Sheet sheet = workbook.getSheetAt(i); if (parsingUtil.isSheetAllowedToProcess(request, sheet.getSheetName(), localeResponse)) { + addFacilityNameToSheet(sheet, assignedFacilityColHeader, boundaryCodeToFacility, mappedValues); + } + } + } - // Get column index of assigned facility name in the sheet being processed - Integer indexOfFacility = (int) sheet.getRow(0).getLastCellNum(); - - // Create a new column for assigned facility name - Cell facilityColHeader = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); - excelStylingUtil.styleCell(facilityColHeader); - facilityColHeader.setCellValue(assignedFacilityColHeader); - - // Get column index of boundary code in the sheet being processed from map of col name and index - Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); - Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, - parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); - - // Get a list of boundary codes - List boundaryCodes = enrichmentUtil.getBoundaryCodesFromTheSheet(sheet, request, fileStoreId); + /** + * Collects boundary codes from all eligible sheets in the workbook, fetches census records for these boundaries, + * and maps each boundary code to its assigned facility name obtained from the census data. + * + * @param workbook the workbook containing the sheets. + * @param request the plan configuration request with boundary code details. + * @param fileStoreId the associated file store ID for filtering. + * @return a map of boundary codes to their assigned facility names. + */ + private Map getBoundaryCodeToFacilityMap(Workbook workbook, PlanConfigurationRequest request, String fileStoreId) { + List boundaryCodes = new ArrayList<>(); - //Getting census records for the list of boundaryCodes - List censusList = enrichmentUtil.getCensusRecordsForEnrichment(request, boundaryCodes); + for (int i = 0; i < workbook.getNumberOfSheets(); i++) { + Sheet sheet = workbook.getSheetAt(i); + if (parsingUtil.isSheetAllowedToProcess(request, sheet.getSheetName(), localeUtil.searchLocale(request))) { + boundaryCodes.addAll(enrichmentUtil.getBoundaryCodesFromTheSheet(sheet, request, fileStoreId)); + } + } - // Create a map of boundary code to facility assigned for the boundary - Map boundaryCodeToFacility = censusList.stream() - .collect(Collectors.toMap(Census::getBoundaryCode, census -> (String) parsingUtil.extractFieldsFromJsonObject(census.getAdditionalDetails(), FACILITY_NAME))); + List censusList = enrichmentUtil.getCensusRecordsForEnrichment(request, boundaryCodes); + return censusList.stream() + .collect(Collectors.toMap( + Census::getBoundaryCode, + census -> (String) parsingUtil.extractFieldsFromJsonObject(census.getAdditionalDetails(), FACILITY_NAME))); + } - // for each boundary code in the sheet add the name of the facility assigned to it. - for (Row row : sheet) { - // Skip the header row and empty rows - if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { - continue; - } + /** + * Processes a given sheet by adding a new column for assigned facilities and populating + * each row with the corresponding facility name based on the boundary code. + * + * @param sheet the sheet being processed. + * @param assignedFacilityColHeader the header for the new assigned facility column. + * @param boundaryCodeToFacility the mapping of boundary codes to assigned facilities. + * @param mappedValues a map of 'MappedTo' to 'MappedFrom' values. + */ + private void addFacilityNameToSheet(Sheet sheet, String assignedFacilityColHeader, Map boundaryCodeToFacility, Map mappedValues) { + int indexOfFacility = createAssignedFacilityColumn(sheet, assignedFacilityColHeader); + Map columnNameIndexMap = parsingUtil.getAttributeNameIndexFromExcel(sheet); + int indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, parsingUtil.sortColumnByIndex(columnNameIndexMap), mappedValues); - // Get the boundaryCode in the current row - Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); - String boundaryCode = boundaryCodeCell.getStringCellValue(); + for (Row row : sheet) { + if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { + continue; + } - Cell facilityCell = row.getCell(indexOfFacility); - if (facilityCell == null) { - facilityCell = row.createCell(indexOfFacility, CellType.STRING); - } + String boundaryCode = row.getCell(indexOfBoundaryCode).getStringCellValue(); - // Setting facility name for the boundary from boundaryCodeToFacility map - facilityCell.setCellValue(boundaryCodeToFacility.get(boundaryCode)); - } + Cell facilityCell = row.getCell(indexOfFacility); + if (facilityCell == null) { + facilityCell = row.createCell(indexOfFacility, CellType.STRING); } + + facilityCell.setCellValue(boundaryCodeToFacility.getOrDefault(boundaryCode, "")); } + } + /** + * Adds a new column for the assigned facility name in the provided sheet, styles the header cell, + * and returns the index of the newly created column. + * + * @param sheet the sheet where the column is to be added. + * @param assignedFacilityColHeader the header for the new column. + * @return the index of the newly created column. + */ + private int createAssignedFacilityColumn(Sheet sheet, String assignedFacilityColHeader) { + int indexOfFacility = (int) sheet.getRow(0).getLastCellNum(); + Cell facilityColHeader = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); + excelStylingUtil.styleCell(facilityColHeader); + facilityColHeader.setCellValue(assignedFacilityColHeader); + return indexOfFacility; } } + From d465e1bc322d532ad5c5004a74572a4a7d780fe8 Mon Sep 17 00:00:00 2001 From: Tanishi Goyal Date: Fri, 27 Dec 2024 16:43:37 +0530 Subject: [PATCH 27/29] Adding function comments --- .../util/OutputEstimationGenerationUtil.java | 76 ------------------- 1 file changed, 76 deletions(-) diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java index ae72a60c007..71b3ac8b656 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java @@ -85,82 +85,6 @@ public void processSheetForHeaderLocalization(Sheet sheet, Map l } -// /** -// * For each boundary code in the sheet being processed, adds the name of the facility mapped to that boundary code. -// * -// * @param workbook the workbook. -// * @param request the plan configuration request. -// * @param fileStoreId the associated file store ID. -// */ -// public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest request, String fileStoreId) { -// LocaleResponse localeResponse = localeUtil.searchLocale(request); -// -// String assignedFacilityColHeader = localeUtil.localeSearch(localeResponse.getMessages(), HCM_MICROPLAN_SERVING_FACILITY); -// assignedFacilityColHeader = assignedFacilityColHeader != null ? assignedFacilityColHeader : HCM_MICROPLAN_SERVING_FACILITY; -// -// // Creating a map of MappedTo and MappedFrom values from resource mapping -// Map mappedValues = request.getPlanConfiguration().getResourceMapping().stream() -// .filter(f -> f.getFilestoreId().equals(fileStoreId)) -// .collect(Collectors.toMap( -// ResourceMapping::getMappedTo, -// ResourceMapping::getMappedFrom, -// (existing, replacement) -> existing, -// LinkedHashMap::new -// )); -// -// for (int i = 0; i < workbook.getNumberOfSheets(); i++) { -// Sheet sheet = workbook.getSheetAt(i); -// if (parsingUtil.isSheetAllowedToProcess(request, sheet.getSheetName(), localeResponse)) { -// -// // Get column index of assigned facility name in the sheet being processed -// Integer indexOfFacility = (int) sheet.getRow(0).getLastCellNum(); -// -// // Create a new column for assigned facility name -// Cell facilityColHeader = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); -// excelStylingUtil.styleCell(facilityColHeader); -// facilityColHeader.setCellValue(assignedFacilityColHeader); -// -// // Get column index of boundary code in the sheet being processed from map of col name and index -// Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); -// Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, -// parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); -// -// // Get a list of boundary codes -// List boundaryCodes = enrichmentUtil.getBoundaryCodesFromTheSheet(sheet, request, fileStoreId); -// -// //Getting census records for the list of boundaryCodes -// List censusList = enrichmentUtil.getCensusRecordsForEnrichment(request, boundaryCodes); -// -// // Create a map of boundary code to facility assigned for the boundary -// Map boundaryCodeToFacility = censusList.stream() -// .collect(Collectors.toMap(Census::getBoundaryCode, census -> (String) parsingUtil.extractFieldsFromJsonObject(census.getAdditionalDetails(), FACILITY_NAME))); -// -// // for each boundary code in the sheet add the name of the facility assigned to it. -// for (Row row : sheet) { -// // Skip the header row and empty rows -// if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { -// continue; -// } -// -// // Get the boundaryCode in the current row -// Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); -// String boundaryCode = boundaryCodeCell.getStringCellValue(); -// -// Cell facilityCell = row.getCell(indexOfFacility); -// if (facilityCell == null) { -// facilityCell = row.createCell(indexOfFacility, CellType.STRING); -// } -// -// // Setting facility name for the boundary from boundaryCodeToFacility map -// facilityCell.setCellValue(boundaryCodeToFacility.get(boundaryCode)); -// } -// } -// } -// -// } -// -// - /** * This is the main method responsible for adding an assigned facility name column to each sheet in the workbook. * It iterates through all the sheets, verifies if they are eligible for processing, retrieves required mappings From 3c3116732a4da3765097b18eab35edb03952298e Mon Sep 17 00:00:00 2001 From: Tanishi Goyal Date: Fri, 3 Jan 2025 13:58:52 +0530 Subject: [PATCH 28/29] Revert "pull from master" This reverts commit 902b0c15a734ae9ba7de333394fe9aa4361170ad, reversing changes made to d465e1bc322d532ad5c5004a74572a4a7d780fe8. --- .github/workflows/branch-name-validator.yml | 36 - .github/workflows/buildWorkbenchUI.yml | 64 + .github/workflows/publishAllPackages.yml | 25 + .../workflows/publishAllPackagesRelease.yml | 20 + .github/workflows/publishProjectFactory.yml | 115 +- .vscode/launch.json | 18 - .vscode/settings.json | 3 - CODEOWNERS | 4 +- .../main/java/org/egov/pgr/util/HRMSUtil.java | 8 +- .../validator/ServiceRequestValidator.java | 4 +- .../pgr/web/controllers/MockController.java | 2 +- .../org/egov/pgr/web/models/Workflow.java | 4 - core-services/service-request/CHANGELOG.md | 4 - core-services/service-request/pom.xml | 2 +- .../egov/servicerequest/error/ErrorCode.java | 2 - .../validators/ServiceRequestValidator.java | 24 +- .../web/models/AttributeDefinition.java | 6 +- .../web/models/AttributeValue.java | 2 +- .../servicerequest/web/models/Service.java | 2 +- .../web/models/ServiceDefinition.java | 4 +- ...115143930__servicedefinition_alter_ddl.sql | 9 - frontend/micro-ui/.gitignore | 32 + frontend/micro-ui/Jenkinsfile | 3 + frontend/micro-ui/README.md | 139 + frontend/micro-ui/package.json | 4 + frontend/micro-ui/web/.babelrc | 5 + frontend/micro-ui/web/.env.sample | 3 + frontend/micro-ui/web/CHANGELOG.md | 7 + frontend/micro-ui/web/docker/Dockerfile | 25 + frontend/micro-ui/web/docker/devDockerfile | 26 + frontend/micro-ui/web/docker/masDockerfile | 25 + frontend/micro-ui/web/docker/nginx.conf | 12 + frontend/micro-ui/web/envs.js | 0 frontend/micro-ui/web/install-deps.sh | 14 + .../web/micro-ui-internals/.gitignore | 143 + .../web/micro-ui-internals/.prettierignore | 23 + .../web/micro-ui-internals/.prettierrc.json | 3 + .../micro-ui/web/micro-ui-internals/README.md | 100 + .../micro-ui/web/micro-ui-internals/clean.sh | 28 + .../micro-ui-internals/example/.env-health-qa | 7 + .../micro-ui-internals/example/.env-mz-prod | 7 + .../micro-ui-internals/example/.env-mz-uat | 7 + .../example/.env-unifieddev | 9 + .../micro-ui-internals/example/package.json | 40 + .../example/public/index.html | 34 + .../example/src/UICustomizations.js | 789 +++ .../micro-ui-internals/example/src/index.js | 84 + .../example/src/setupProxy.js | 101 + .../web/micro-ui-internals/package.json | 59 + .../micro-ui-internals/packages/css/README.md | 62 + .../packages/css/gulpfile.js | 71 + .../packages/css/package.json | 65 + .../packages/css/postcss.config.js | 55 + .../css/src/components/microplanning.scss | 363 ++ .../packages/css/src/index.scss | 13 + .../css/src/pages/employee/campaign.scss | 109 + .../css/src/pages/employee/campaignCycle.scss | 331 ++ .../css/src/pages/employee/coreOverride.scss | 173 + .../css/src/pages/employee/index.scss | 481 ++ .../packages/css/src/typography.scss | 512 ++ .../packages/css/tailwind.config.js | 233 + .../modules/campaign-manager/README.md | 159 + .../modules/campaign-manager/package.json | 51 + .../modules/campaign-manager/src/Module.js | 141 + .../src/components/AddProductField.js | 144 + .../src/components/BulkUpload.js | 202 + .../src/components/CampaignCard.js | 71 + .../src/components/CampaignDates.js | 122 + .../components/CampaignDocumentsPreview.js | 92 + .../src/components/CampaignHeader.js | 32 + .../src/components/CampaignName.js | 66 + .../components/CampaignResourceDocuments.js | 50 + .../src/components/CampaignSummary.js | 484 ++ .../src/components/CampaignType.js | 143 + .../src/components/CycleDataPreview.js | 186 + .../src/components/CycleDetaisPreview.js | 143 + .../src/components/DetailsTable.js | 76 + .../src/components/DocumentIcon.js | 29 + .../src/components/PlusMinusInput.js | 47 + .../src/components/RemovableTagNew.js | 16 + .../src/components/SelectingBoundaries.js | 542 ++ .../src/components/TimelineCampaign.js | 46 + .../src/components/UploadData.js | 1163 ++++ .../src/components/XlsPreview.js | 69 + .../src/components/icons/DustbinIcon.js | 10 + .../src/components/icons/XlsxFile.js | 32 + .../src/configs/CampaignConfig.js | 267 + .../src/configs/UICustomizations.js | 472 ++ .../src/configs/addProductConfig.js | 19 + .../src/configs/attributeConfig.js | 23 + .../src/configs/baseTimeOut.js | 6 + .../src/configs/deliveryConfig.js | 206 + .../src/configs/headerConfig.js | 20 + .../src/configs/mailConfig.js | 5 + .../src/configs/myCampaignConfig.js | 667 +++ .../src/configs/operatorConfig.js | 27 + .../src/configs/previewConfig.js | 124 + .../src/configs/productType.js | 15 + .../src/configs/schemaConfig.js | 80 + .../campaign-manager/src/hooks/index.js | 47 + .../hooks/services/createCampaignService.js | 19 + .../hooks/services/updateCampaignService.js | 20 + .../src/hooks/services/useSearchCampaign.js | 21 + .../src/hooks/useCreateCampaign.js | 10 + .../src/hooks/useCreateProduct.js | 24 + .../src/hooks/useCreateProductVariant.js | 24 + .../src/hooks/useGenerateIdCampaign.js | 26 + .../src/hooks/useParallelSearch.js | 88 + .../src/hooks/useProductList.js | 53 + .../src/hooks/useResourceData.js | 107 + .../src/hooks/useUpdateCampaign.js | 10 + .../src/pages/employee/AddProduct.js | 161 + .../src/pages/employee/CycleConfiguration.js | 248 + .../src/pages/employee/MyCampaign.js | 80 + .../src/pages/employee/Response.js | 65 + .../src/pages/employee/SetupCampaign.js | 1491 +++++ .../deliveryRule/AddDeliverycontext.js | 813 +++ .../deliveryRule/AddProductscontext.js | 290 + .../employee/deliveryRule/MultiTabcontext.js | 265 + .../src/pages/employee/deliveryRule/index.js | 531 ++ .../src/pages/employee/index.js | 102 + .../campaign-manager/src/utils/TourSteps.js | 144 + .../src/utils/downloadExcel.js | 46 + .../campaign-manager/src/utils/index.js | 6 + .../modules/hcm-microplanning/package.json | 62 + .../modules/hcm-microplanning/src/Module.js | 99 + .../src/components/CommonComponents.js | 61 + .../src/components/CustomScaleControl.js | 41 + .../src/components/Hypothesis.js | 607 ++ .../src/components/JsonPreviewInExcelForm.js | 113 + .../src/components/Mapping.js | 445 ++ .../src/components/MappingHelperComponents.js | 513 ++ .../src/components/MicroplanCreatedScreen.js | 111 + .../src/components/MicroplanDetails.js | 294 + .../src/components/MicroplanPreview.js | 478 ++ .../MicroplanPreviewHelperCompoenents.js | 434 ++ .../src/components/MicroplanningCard.js | 34 + .../src/components/MicroplanningHeader.js | 29 + .../hcm-microplanning/src/components/Modal.js | 158 + .../src/components/Nagivator.js | 272 + .../src/components/RuleEngine.js | 876 +++ .../src/components/Upload.js | 1137 ++++ .../src/components/UploadHelperComponents.js | 299 + .../src/components/ZoomControl.js | 29 + .../src/components/resourceMapping.js | 187 + .../src/configs/UICustomizations.js | 324 ++ .../src/configs/constants.js | 36 + .../src/configs/timeLineOptions.json | 40 + .../src/configs/tourSteps.js | 193 + .../hcm-microplanning/src/hooks/index.js | 42 + .../src/hooks/useCreatePlanConfig.js | 8 + .../src/hooks/useGenerateIdCampaign.js | 26 + .../src/hooks/useNumberFormatter.js | 21 + .../src/hooks/useSavedMicroplans.js | 23 + .../src/hooks/useSearchCampaign.js | 8 + .../src/hooks/useSearchPlanConfig.js | 8 + .../src/hooks/useUpdatePlanConfig.js | 8 + .../hcm-microplanning/src/icons/Svg.js | 217 + .../src/pages/employee/CreateMicroplan.js | 288 + .../src/pages/employee/Guidelines.js | 54 + .../src/pages/employee/SavedMicroplans.js | 200 + .../src/pages/employee/SelectCampaign.js | 226 + .../src/pages/employee/index.js | 128 + .../src/services/CreatePlanConfig.js | 19 + .../hcm-microplanning/src/services/Search.js | 181 + .../src/services/SearchCampaignConfig.js | 22 + .../src/services/SearchPlanConfig.js | 19 + .../src/services/UpdatePlanConfig.js | 18 + .../src/services/searchSavedPlans.js | 67 + .../hcm-microplanning/src/utils/context.js | 31 + .../src/utils/createTemplate.js | 485 ++ .../hcm-microplanning/src/utils/excelUtils.js | 150 + .../src/utils/excelValidations.js | 199 + .../src/utils/exceltojson.js | 99 + .../src/utils/geojsonValidations.js | 234 + .../hcm-microplanning/src/utils/index.js | 478 ++ .../src/utils/jsonToExcelBlob.js | 72 + .../src/utils/mappingUtils.js | 760 +++ .../src/utils/microplanPreviewUtils.js | 413 ++ .../src/utils/processHierarchyAndData.js | 351 ++ .../src/utils/updateSessionUtils.js | 486 ++ .../src/utils/uploadUtils.js | 880 +++ .../Modal/AttendanceActionModal.js | 133 + .../Modal/BPAActionModal.js | 283 + .../Modal/BPAREGActionModal.js | 153 + .../Modal/ExpenditureActionModal.js | 190 + .../Modal/FSMActionModal.js | 298 + .../Modal/NOCActionModal.js | 169 + .../ApplicationDetails/Modal/PTActionModal.js | 190 + .../ApplicationDetails/Modal/TLActionModal.js | 166 + .../Modal/WNSActionModal.js | 261 + .../Modal/WorksActionModal.js | 262 + .../ApplicationDetails/Modal/index.js | 49 + .../components/ApplicationDetailsActionBar.js | 80 + .../components/ApplicationDetailsContent.js | 484 ++ .../components/ApplicationDetailsToast.js | 74 + .../ApplicationDetailsWarningPopup.js | 54 + .../components/BPADocuments.js | 234 + .../components/DocumentsPreview.js | 49 + .../components/InfoDetails.js | 34 + .../components/InspectionReport.js | 49 + .../components/NOCDocuments.js | 202 + .../components/PermissionCheck.js | 87 + .../components/PropertyDocuments.js | 83 + .../components/PropertyEstimates.js | 39 + .../components/PropertyFloors.js | 49 + .../components/PropertyOwners.js | 94 + .../ApplicationDetails/components/Reason.js | 10 + .../components/ScruntinyDetails.js | 46 + .../components/SubOccupancyTable.js | 126 + .../components/SubWorkTableDetails.js | 77 + .../components/TLCaption.js | 34 + .../components/TLTradeAccessories.js | 52 + .../components/TLTradeUnits.js | 51 + .../components/ViewBreakup.js | 73 + .../components/WSAdditonalDetails.js | 399 ++ .../components/WSFeeEstimation.js | 346 ++ .../components/WeekDateRange.js | 30 + .../ApplicationDetails/config/AcceptDso.js | 45 + .../ApplicationDetails/config/AssignDso.js | 115 + .../config/BPAApproverApplication.js | 77 + .../config/BPAREGApproverApplication.js | 71 + .../config/CompleteApplication.js | 46 + .../config/NOCApproverApplication.js | 79 + .../config/PTApproverApplication.js | 66 + .../config/PTAssessProperty.js | 26 + .../ApplicationDetails/config/ReassignDso.js | 101 + .../config/RejectApplication.js | 31 + .../config/TLApproverApplication.js | 83 + .../config/WSApproverApplication.js | 73 + .../config/WSDisconnectApplication.js | 89 + .../config/configApproveModal.js | 53 + .../config/configAttendanceApproveModal.js | 27 + .../config/configAttendanceCheckModal.js | 93 + .../config/configAttendanceRejectModal.js | 61 + .../config/configCheckModal.js | 105 + .../config/configRejectModal.js | 127 + .../config/configViewBillApproveModal.js | 57 + .../config/configViewBillCheckModal.js | 107 + .../config/configViewBillRejectModal.js | 59 + .../ApplicationDetails/config/index.js | 47 + .../templates/ApplicationDetails/index.js | 368 ++ .../web/micro-ui-internals/publish-develop.sh | 20 + .../web/micro-ui-internals/publish.sh | 20 + .../web/micro-ui-internals/scripts/create.sh | 3 + .../web/micro-ui-internals/scripts/deploy.sh | 8 + .../web/micro-ui-internals/scripts/jenkins.sh | 3 + .../web/micro-ui-internals/scripts/run.sh | 32 + .../micro-ui/web/micro-ui-internals/test.js | 31 + frontend/micro-ui/web/microplan/App.js | 61 + frontend/micro-ui/web/microplan/Dockerfile | 30 + .../micro-ui/web/microplan/install-deps.sh | 18 + .../micro-ui/web/microplan/inter-package.json | 61 + frontend/micro-ui/web/microplan/nginx.conf | 12 + frontend/micro-ui/web/microplan/package.json | 80 + .../micro-ui/web/microplan/webpack.config.js | 52 + frontend/micro-ui/web/package.json | 85 + frontend/micro-ui/web/public/index.html | 38 + frontend/micro-ui/web/public/robots.txt | 3 + frontend/micro-ui/web/src/App.js | 74 + .../micro-ui/web/src/ComponentRegistry.js | 11 + .../src/Customisations/UICustomizations.js | 428 ++ .../micro-ui/web/src/Customisations/index.js | 19 + .../web/src/Customisations/pt/index.js | 13 + .../pt/pageComponents/PTAllotmentDetails.js | 64 + .../pt/pageComponents/PTBusinessDetails.js | 68 + .../pt/pageComponents/PTVasikaDetails.js | 79 + .../pt/pageComponents/PropertyUsageType.js | 134 + .../src/Customisations/tl/TLCustomisation.js | 5 + .../web/src/Customisations/tl/index.js | 7 + .../tl/pageComponents/PropertyUsageType.js | 136 + frontend/micro-ui/web/src/index.css | 0 frontend/micro-ui/web/src/index.js | 62 + frontend/micro-ui/web/src/setupProxy.js | 30 + frontend/micro-ui/web/webpack.config.js | 43 + frontend/micro-ui/web/workbench/App.js | 72 + frontend/micro-ui/web/workbench/Dockerfile | 29 + .../micro-ui/web/workbench/install-deps.sh | 18 + .../micro-ui/web/workbench/inter-package.json | 58 + frontend/micro-ui/web/workbench/nginx.conf | 12 + frontend/micro-ui/web/workbench/package.json | 89 + .../micro-ui/web/workbench/webpack.config.js | 44 + .../repository/rowmapper/CensusRowMapper.java | 26 +- health-services/facility/pom.xml | 4 +- .../repository/FacilityRepository.java | 21 +- .../rowmapper/FacilityRowMapper.java | 2 +- .../facility/service/FacilityService.java | 21 +- .../validator/FNonExistentValidator.java | 2 +- .../validator/FRowVersionValidator.java | 2 +- .../controllers/FacilityApiController.java | 7 +- .../NonExistentEntityValidatorTest.java | 8 +- .../validator/RowVersionValidatorTest.java | 8 +- health-services/household/CHANGELOG.md | 12 +- health-services/household/pom.xml | 2 +- health-services/individual/CHANGELOG.md | 8 +- health-services/individual/pom.xml | 2 +- .../libraries/health-services-common/pom.xml | 10 +- .../data/repository/GenericRepository.java | 48 - .../libraries/health-services-models/pom.xml | 2 +- .../models/facility/FacilityBulkResponse.java | 23 +- .../individual/IndividualBulkResponse.java | 24 +- .../project/ProjectFacilityBulkResponse.java | 23 +- .../project/ProjectResourceBulkResponse.java | 5 - .../project/ProjectStaffBulkResponse.java | 27 +- .../project/useraction/UserActionSearch.java | 2 - .../hfreferral/HFReferralBulkResponse.java | 18 - .../models/stock/StockBulkResponse.java | 26 +- .../StockReconciliationBulkResponse.java | 25 +- .../rowmapper/PlanConfigRowMapper.java | 57 +- .../repository/rowmapper/PlanRowMapper.java | 40 +- .../{enrichment => }/PlanEnricher.java | 2 +- .../main/java/digit/service/PlanService.java | 4 +- .../{validator => }/PlanValidator.java | 9 +- health-services/project-factory/CHANGELOG.md | 12 - health-services/project-factory/Dockerfile | 4 +- health-services/project-factory/README.md | 125 +- .../V20240315110400__resource_details_ddl.sql | 46 + .../V20240315110513__campaign_details_ddl.sql | 16 + ...01154500__campaign_details_add_columns.sql | 3 + ...2134500__campaign_details_alter_column.sql | 2 + ...0154500__campaign_details_alter_column.sql | 3 + .../V20240416170000__generate_add_column.sql | 2 + .../V20240427174100__campaign_add_column.sql | 2 + ...2143500__resource_details_alter_column.sql | 2 + ...40826145500__add_resource_and_campaign.sql | 92 - .../V20240829125000__add_index_on_tables.sql | 5 - ...rentid_isactive_in_eg_campaign_details.sql | 5 - ...remove_campaign_name_unique_constraint.sql | 2 - ...241013115000__add_hierarchytype_column.sql | 1 - .../project-factory/migration/migrate.sh | 1 - .../project-factory/package-lock.json | 3450 ++++++----- health-services/project-factory/package.json | 9 +- .../project-factory/postman_collection.json | 413 +- .../src/server/api/campaignApis.ts | 1710 ++---- .../src/server/api/coreApis.ts | 259 - .../src/server/api/genericApis.ts | 673 +-- .../src/server/api/healthApis.ts | 28 - .../src/server/api/microplanApis.ts | 124 - .../project-factory/src/server/app.ts | 90 +- .../src/server/config/constants.ts | 56 +- .../src/server/config/createAndSearch.ts | 153 +- .../src/server/config/index.ts | 65 +- .../server/config/models/SearchCriteria.ts | 3 - .../models/campaignDetailsDraftSchema.ts | 5 +- .../config/models/createRequestSchema.ts | 5 +- .../config/models/downloadRequestSchema.ts | 24 +- .../config/models/generateRequestSchema.ts | 9 +- .../config/models/searchCampaignDetails.ts | 3 - .../campaignManage.controller.ts | 71 +- .../localisation.controller.ts | 49 +- .../src/server/kafka/Listener.ts | 112 +- .../src/server/kafka/Producer.ts | 137 +- .../src/server/models/Boundary.d.ts | 115 - .../src/server/models/MDMS.d.ts | 144 - .../src/server/models/index.ts | 8 - .../server/service/campaignManageService.ts | 59 +- .../src/server/service/dataManageService.ts | 95 +- .../utils/boundariesConsolidationUtils.ts | 44 - .../src/server/utils/boundaryUtils.ts | 53 - .../src/server/utils/campaignMappingUtils.ts | 629 +- .../src/server/utils/campaignUtils.ts | 5159 +++++------------ .../src/server/utils/excelUtils.ts | 176 +- .../src/server/utils/generateUtils.ts | 104 - .../src/server/utils/genericUtils.ts | 707 +-- .../src/server/utils/localisationUtils.ts | 34 +- .../src/server/utils/logger/index.ts | 19 +- .../src/server/utils/microplanIntergration.ts | 985 ---- .../src/server/utils/microplanUtils.ts | 493 -- .../utils/onGoingCampaignUpdateUtils.ts | 768 --- .../src/server/utils/pollUtils.ts | 193 - .../src/server/utils/processTrackUtils.ts | 234 +- .../src/server/utils/redisUtils.ts | 52 +- .../src/server/utils/request.ts | 44 +- .../src/server/utils/targetUtils.ts | 137 - .../localisationMessageConstructor.ts | 123 +- .../utils/transforms/projectTypeUtils.ts | 67 +- .../transforms/searchResponseConstructor.ts | 2 - .../server/validators/campaignValidators.ts | 839 +-- .../src/server/validators/genericValidator.ts | 76 +- .../server/validators/microplanValidators.ts | 323 -- .../project-factory/tsconfig.debug.json | 68 - health-services/project-factory/tsconfig.json | 2 +- health-services/project-factory/yarn.lock | 2295 ++++---- health-services/project/CHANGELOG.md | 1 - health-services/project/pom.xml | 4 +- .../repository/ProjectFacilityRepository.java | 11 +- .../rowmapper/DocumentRowMapper.java | 2 +- .../rowmapper/LocationCaptureRowMapper.java | 2 +- .../rowmapper/ProjectAddressRowMapper.java | 2 +- .../ProjectBeneficiaryRowMapper.java | 2 +- .../rowmapper/ProjectFacilityRowMapper.java | 2 +- .../rowmapper/ProjectResourceRowMapper.java | 2 +- .../rowmapper/ProjectRowMapper.java | 2 +- .../rowmapper/ProjectStaffRowMapper.java | 2 +- .../rowmapper/ProjectTaskRowMapper.java | 2 +- .../repository/rowmapper/TargetRowMapper.java | 2 +- .../rowmapper/TaskResourceRowMapper.java | 2 +- .../rowmapper/UserActionRowMapper.java | 2 +- .../service/ProjectFacilityService.java | 31 +- .../service/ProjectResourceService.java | 18 +- .../egov/project/service/ProjectService.java | 2 +- .../project/service/ProjectStaffService.java | 20 +- .../service/enrichment/ProjectEnrichment.java | 2 +- .../ProjectTaskEnrichmentService.java | 2 +- .../org/egov/project/util/BoundaryUtil.java | 16 +- .../java/org/egov/project/util/MDMSUtils.java | 8 +- .../egov/project/util/ProjectServiceUtil.java | 2 +- .../beneficiary/BeneficiaryValidator.java | 8 +- .../validator/staff/PsUserIdValidator.java | 14 +- .../task/PtResourceQuantityValidator.java | 8 +- .../web/controllers/ProjectApiController.java | 10 +- .../ProjectResourceApiController.java | 8 +- .../src/main/resources/application.properties | 1 - .../ProjectBeneficiaryServiceCreateTest.java | 2 +- .../ProjectBeneficiaryServiceUpdateTest.java | 2 +- .../ProjectFacilityServiceSearchTest.java | 14 +- .../ProjectStaffServiceSearchTest.java | 13 +- .../ProjectFacilityApiControllerTest.java | 6 +- .../ProjectStaffApiControllerTest.java | 3 +- .../referralmanagement/CHANGELOG.md | 1 - health-services/referralmanagement/pom.xml | 4 +- .../repository/HFReferralRepository.java | 19 +- .../rowmapper/HFReferralRowMapper.java | 2 +- .../rowmapper/ReferralRowMapper.java | 2 +- .../rowmapper/SideEffectRowMapper.java | 2 +- .../service/HFReferralService.java | 16 +- .../service/MasterDataService.java | 14 +- .../util/ValidatorUtil.java | 2 +- .../HfrNonExistentEntityValidator.java | 3 +- .../hfreferral/HfrRowVersionValidator.java | 2 +- .../controllers/HFReferralApiController.java | 8 +- .../processor/config/ServiceConstants.java | 11 + .../egov/processor/service/ExcelParser.java | 58 +- .../egov/processor/util/EnrichmentUtil.java | 11 +- .../org/egov/processor/util/ParsingUtil.java | 73 +- health-services/stock/CHANGELOG.md | 1 - health-services/stock/pom.xml | 4 +- .../StockReconciliationRowMapper.java | 2 +- .../repository/rowmapper/StockRowMapper.java | 2 +- .../service/StockReconciliationService.java | 18 +- .../org/egov/stock/service/StockService.java | 18 +- .../org/egov/stock/util/ValidatorUtil.java | 2 +- .../web/controllers/StockApiController.java | 5 +- .../StockReconciliationApiController.java | 8 +- 444 files changed, 43960 insertions(+), 16300 deletions(-) delete mode 100644 .github/workflows/branch-name-validator.yml create mode 100644 .github/workflows/buildWorkbenchUI.yml create mode 100644 .github/workflows/publishAllPackages.yml create mode 100644 .github/workflows/publishAllPackagesRelease.yml delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json delete mode 100644 core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql create mode 100644 frontend/micro-ui/.gitignore create mode 100644 frontend/micro-ui/Jenkinsfile create mode 100644 frontend/micro-ui/README.md create mode 100644 frontend/micro-ui/package.json create mode 100644 frontend/micro-ui/web/.babelrc create mode 100644 frontend/micro-ui/web/.env.sample create mode 100644 frontend/micro-ui/web/CHANGELOG.md create mode 100644 frontend/micro-ui/web/docker/Dockerfile create mode 100644 frontend/micro-ui/web/docker/devDockerfile create mode 100644 frontend/micro-ui/web/docker/masDockerfile create mode 100644 frontend/micro-ui/web/docker/nginx.conf create mode 100644 frontend/micro-ui/web/envs.js create mode 100755 frontend/micro-ui/web/install-deps.sh create mode 100644 frontend/micro-ui/web/micro-ui-internals/.gitignore create mode 100644 frontend/micro-ui/web/micro-ui-internals/.prettierignore create mode 100644 frontend/micro-ui/web/micro-ui-internals/.prettierrc.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/README.md create mode 100644 frontend/micro-ui/web/micro-ui-internals/clean.sh create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/package.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/public/index.html create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/package.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/README.md create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/package.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignCard.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignHeader.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignResourceDocuments.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDataPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/baseTimeOut.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddProductscontext.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/publish-develop.sh create mode 100644 frontend/micro-ui/web/micro-ui-internals/publish.sh create mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/create.sh create mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh create mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh create mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/run.sh create mode 100644 frontend/micro-ui/web/micro-ui-internals/test.js create mode 100644 frontend/micro-ui/web/microplan/App.js create mode 100644 frontend/micro-ui/web/microplan/Dockerfile create mode 100644 frontend/micro-ui/web/microplan/install-deps.sh create mode 100644 frontend/micro-ui/web/microplan/inter-package.json create mode 100644 frontend/micro-ui/web/microplan/nginx.conf create mode 100644 frontend/micro-ui/web/microplan/package.json create mode 100644 frontend/micro-ui/web/microplan/webpack.config.js create mode 100644 frontend/micro-ui/web/package.json create mode 100644 frontend/micro-ui/web/public/index.html create mode 100644 frontend/micro-ui/web/public/robots.txt create mode 100644 frontend/micro-ui/web/src/App.js create mode 100644 frontend/micro-ui/web/src/ComponentRegistry.js create mode 100644 frontend/micro-ui/web/src/Customisations/UICustomizations.js create mode 100644 frontend/micro-ui/web/src/Customisations/index.js create mode 100644 frontend/micro-ui/web/src/Customisations/pt/index.js create mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js create mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js create mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js create mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js create mode 100644 frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js create mode 100644 frontend/micro-ui/web/src/Customisations/tl/index.js create mode 100644 frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js create mode 100644 frontend/micro-ui/web/src/index.css create mode 100644 frontend/micro-ui/web/src/index.js create mode 100644 frontend/micro-ui/web/src/setupProxy.js create mode 100644 frontend/micro-ui/web/webpack.config.js create mode 100644 frontend/micro-ui/web/workbench/App.js create mode 100644 frontend/micro-ui/web/workbench/Dockerfile create mode 100755 frontend/micro-ui/web/workbench/install-deps.sh create mode 100644 frontend/micro-ui/web/workbench/inter-package.json create mode 100644 frontend/micro-ui/web/workbench/nginx.conf create mode 100644 frontend/micro-ui/web/workbench/package.json create mode 100644 frontend/micro-ui/web/workbench/webpack.config.js rename health-services/plan-service/src/main/java/digit/service/{enrichment => }/PlanEnricher.java (99%) rename health-services/plan-service/src/main/java/digit/service/{validator => }/PlanValidator.java (99%) create mode 100644 health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql create mode 100644 health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql create mode 100644 health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql create mode 100644 health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql create mode 100644 health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql create mode 100644 health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql create mode 100644 health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql create mode 100644 health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql delete mode 100644 health-services/project-factory/migration/main/V20240826145500__add_resource_and_campaign.sql delete mode 100644 health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql delete mode 100644 health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql delete mode 100644 health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql delete mode 100644 health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql delete mode 100644 health-services/project-factory/src/server/api/coreApis.ts delete mode 100644 health-services/project-factory/src/server/api/healthApis.ts delete mode 100644 health-services/project-factory/src/server/api/microplanApis.ts delete mode 100644 health-services/project-factory/src/server/models/Boundary.d.ts delete mode 100644 health-services/project-factory/src/server/models/MDMS.d.ts delete mode 100644 health-services/project-factory/src/server/models/index.ts delete mode 100644 health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts delete mode 100644 health-services/project-factory/src/server/utils/generateUtils.ts delete mode 100644 health-services/project-factory/src/server/utils/microplanIntergration.ts delete mode 100644 health-services/project-factory/src/server/utils/microplanUtils.ts delete mode 100644 health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts delete mode 100644 health-services/project-factory/src/server/utils/pollUtils.ts delete mode 100644 health-services/project-factory/src/server/utils/targetUtils.ts delete mode 100644 health-services/project-factory/src/server/validators/microplanValidators.ts delete mode 100644 health-services/project-factory/tsconfig.debug.json diff --git a/.github/workflows/branch-name-validator.yml b/.github/workflows/branch-name-validator.yml deleted file mode 100644 index d613cfe22d6..00000000000 --- a/.github/workflows/branch-name-validator.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Enforce Branch Naming Convention - -on: - push: - branches: - - "*" - pull_request: - branches: - - "*" - -jobs: - branch-name-check: - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@v4 - - - name: Enforce branch naming convention - run: | - # Get the branch name - branch_name=$(echo "${GITHUB_REF#refs/heads/}") - - # Define the branch name pattern - branch_regex="^(master|develop|(HCMPRE|HCMPOST|HCMSUB)-[0-9]{3,}-[a-zA-Z0-9-]+)$" - - # Check if the branch name matches the pattern - if [[ ! "$branch_name" =~ $branch_regex ]]; then - echo "Branch name '$branch_name' does not follow the required naming convention." - echo "Branch names must follow the pattern: (HCMPRE|HCMPOST|HCMSUB)-123-description" - exit 1 - fi - - - name: Success message - run: | - branch_name=$(echo "${GITHUB_REF#refs/heads/}") - echo "Branch name '$branch_name' follows the required naming convention: 'master', 'develop', or (HCMPRE|HCMPOST|HCMSUB)-123-description" diff --git a/.github/workflows/buildWorkbenchUI.yml b/.github/workflows/buildWorkbenchUI.yml new file mode 100644 index 00000000000..1a0c526d1bf --- /dev/null +++ b/.github/workflows/buildWorkbenchUI.yml @@ -0,0 +1,64 @@ +name: Digit Admin Console Build workflow +on: + push: + branches: + - campaign + paths: + - 'micro-ui/web/micro-ui-internals/**' + pull_request: + branches: + - campaign + workflow_dispatch: +jobs: + docker_image-build: + outputs: + run_job_digit_ui: ${{ steps.check_files.outputs.run_job_digit_ui }} + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 2 + - name: Setup Docker + uses: docker/setup-buildx-action@v1 + - name: check modified files + id: check_files + run: | + echo "=============== list modified files ===============" + git diff --name-only HEAD^ HEAD + + echo "========== check paths of modified files ==========" + git diff --name-only HEAD^ HEAD > files.txt + run_job_digit_ui=false + while IFS= read -r file + do + if [[ $file == micro-ui/* ]]; then + echo "This modified file is under the 'digit_ui' folder." + run_job_digit_ui=true + fi + done < files.txt + + # Set the output based on whether the job should run + echo "::set-output name=run_job_digit_ui::$run_job_digit_ui" + echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + echo "COMMIT_ID=${GITHUB_SHA: -8}" >> $GITHUB_ENV # Extract last 8 characters of SHA + echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV + + + + + - name: Login to egovio docker Container Registry + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + run: | + # Authenticate with Docker Hub + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + + - name: Build and Push Docker image for digit-ui + if: ${{ steps.check_files.outputs.run_job_digit_ui == 'true' }} + run: | + docker build -t workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} -f web/workbench/Dockerfile . + docker tag workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + docker push egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + working-directory: micro-ui diff --git a/.github/workflows/publishAllPackages.yml b/.github/workflows/publishAllPackages.yml new file mode 100644 index 00000000000..6bb4b51d612 --- /dev/null +++ b/.github/workflows/publishAllPackages.yml @@ -0,0 +1,25 @@ +name: Node.js Publish UI Packages + +on: + push: + branches: [ 'develop','campaign' ] + paths: + - 'micro-ui/web/micro-ui-internals/**' + + pull_request: + branches: + - 'dev-hcm' + # Push events to branches matching refs/heads/mona/octocat + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 14 + registry-url: https://registry.npmjs.org/ + - run: cd micro-ui/web/micro-ui-internals/ && bash ./publish-develop.sh + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/publishAllPackagesRelease.yml b/.github/workflows/publishAllPackagesRelease.yml new file mode 100644 index 00000000000..ff9b6a3a93f --- /dev/null +++ b/.github/workflows/publishAllPackagesRelease.yml @@ -0,0 +1,20 @@ +name: Node.js Publish UI Packages + +on: + push: + branches: [ 'master' ] + paths: + - 'micro-ui/web/micro-ui-internals/**' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 14 + registry-url: https://registry.npmjs.org/ + - run: cd micro-ui/web/micro-ui-internals/ && bash ./publish.sh + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/publishProjectFactory.yml b/.github/workflows/publishProjectFactory.yml index 33e224b222c..19fde98c7ab 100644 --- a/.github/workflows/publishProjectFactory.yml +++ b/.github/workflows/publishProjectFactory.yml @@ -1,72 +1,77 @@ -name: Project Factory Service Test Builder +name: project factory service docker Image CI on: push: - branches: - - "console" - - "master" + branches: [ "campaign" ] paths: - - 'health-services/project-factory/**' + - 'utilities/project-factory/**' pull_request: - branches: - - "console" - - "master" + branches: [ "campaign" ] jobs: + build: + runs-on: ubuntu-latest steps: - # Step 1: Checkout the repository - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # Fetch all history for tags and branches + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # Fetch all history for tags and branches - # Step 2: Set up environment variables - - name: Set up environment variables - id: env - run: | - echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + - name: Set up environment variables + id: env + run: | + echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV + echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + echo "COMMIT_ID=${GITHUB_SHA: -8}" >> $GITHUB_ENV # Extract last 8 characters of SHA - # Step 3: Build the service Docker image - - name: Build the service Docker image - id: docker_build - working-directory: ./health-services/project-factory - run: | - IMAGE_TAG=egovio/project-factory:${{ env.ACTION_NUMBER }} - docker build . \ - --file Dockerfile \ - --tag $IMAGE_TAG - echo "::set-output name=image_name::$IMAGE_TAG" - echo "Service Docker image built successfully" + - name: Build the service Docker image + id: docker_build + working-directory: ./utilities/project-factory + run: | + IMAGE_TAG=egovio/project-factory:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + docker build . \ + --file Dockerfile \ + --tag $IMAGE_TAG + echo "::set-output name=image_name::$IMAGE_TAG" - # Step 4: Build the database migration Docker image - - name: Build the DB migration Docker image - id: docker_db_build - working-directory: ./health-services/project-factory/migration - run: | - IMAGE_TAG=egovio/project-factory-db:${{ env.ACTION_NUMBER }} - docker build . \ - --file Dockerfile \ - --tag $IMAGE_TAG - echo "::set-output name=db_image_name::$IMAGE_TAG" - echo "DB migration Docker image built successfully" - node_build: - runs-on: ubuntu-latest - - steps: - # Step 1: Checkout the repository - - uses: actions/checkout@v3 + - name: Build the db migration Docker image + id: docker_db_build + working-directory: ./utilities/project-factory/migration + run: | + IMAGE_TAG=egovio/project-factory-db:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + docker build . \ + --file Dockerfile \ + --tag $IMAGE_TAG + echo "::set-output name=db_image_name::$IMAGE_TAG" - # Step 2: Set up Node.js environment - - uses: actions/setup-node@v2 - with: - node-version: 20 - # Step 3: Install dependencies and build for production - - name: Install dependencies and build - working-directory: ./health-services/project-factory - run: | - yarn install - yarn build + - name: Login to Docker Hub and Push Docker Image + working-directory: ./utilities/project-factory + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + IMAGE_NAME: ${{ steps.docker_build.outputs.image_name }} + run: | + # Authenticate with Docker Hub + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + + # Push the image to Docker Hub + docker push $IMAGE_NAME + echo "Docker image pushed: $IMAGE_NAME" + + - name: Login to Docker Hub and Push DB Migration Docker Image + working-directory: ./utilities/project-factory/migration + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + DB_IMAGE_NAME: ${{ steps.docker_db_build.outputs.db_image_name }} + run: | + # Authenticate with Docker Hub + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + + # Push the image to Docker Hub + docker push $DB_IMAGE_NAME + echo "Docker image pushed: $DB_IMAGE_NAME" diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index d61e0ddfd7d..00000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - - { - "type": "node", - "request": "attach", - "name": "Attach to Remote", - "address": "localhost", - "port": 9229, - "localRoot": "${workspaceFolder}", - "remoteRoot": "/app" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 14f60307eb1..00000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.inlineSuggest.showToolbar": "onHover" -} \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS index 7833b872775..cacb23525d2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1 @@ -* @kavi-egov @sathishp-eGov - -health-services/project-factory/ @jagankumar-egov +* @kavi-egov @sathishp-eGov @shashwat-egov diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java b/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java index 4409e39ed35..52416b33f23 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java @@ -32,15 +32,13 @@ public HRMSUtil(ServiceRequestRepository serviceRequestRepository, PGRConfigurat /** * Gets the list of department for the given list of uuids of employees - * - * @param uuids user uuids - * @param employeeUuids employee uuids + * @param uuids * @param requestInfo * @return */ - public List getDepartment(List uuids, List employeeUuids, RequestInfo requestInfo){ + public List getDepartment(List uuids, RequestInfo requestInfo){ - StringBuilder url = getHRMSURI(employeeUuids); + StringBuilder url = getHRMSURI(uuids); RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java b/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java index fe9e1bd148c..e6d154759fc 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java @@ -159,12 +159,10 @@ private void validateDepartment(ServiceRequest request, Object mdmsData){ String serviceCode = request.getService().getServiceCode(); List assignes = request.getWorkflow().getAssignes(); - List hrmsAssignes = request.getWorkflow().getHrmsAssignees(); - if(CollectionUtils.isEmpty(assignes)) return; - List departments = hrmsUtil.getDepartment(assignes, hrmsAssignes, request.getRequestInfo()); + List departments = hrmsUtil.getDepartment(assignes, request.getRequestInfo()); String jsonPath = MDMS_DEPARTMENT_SEARCH.replace("{SERVICEDEF}",serviceCode); diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java b/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java index 92d32234043..16a32b5a77c 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java @@ -113,7 +113,7 @@ public ResponseEntity requestsUpdatePost() throws IOException { public ResponseEntity> requestsTest(@RequestBody RequestInfoWrapper requestInfoWrapper, @RequestParam String tenantId, @RequestParam List uuids) { - List department = hrmsUtil.getDepartment(uuids, uuids, requestInfoWrapper.getRequestInfo()); + List department = hrmsUtil.getDepartment(uuids, requestInfoWrapper.getRequestInfo()); return new ResponseEntity<>(department, HttpStatus.OK); } diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java b/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java index eb949bfce25..b1260ba4e41 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java @@ -35,10 +35,6 @@ public class Workflow { @Valid private List assignes = null; - @JsonProperty("hrmsAssignes") - @Valid - private List hrmsAssignees = null; - @SafeHtml @JsonProperty("comments") private String comments = null; diff --git a/core-services/service-request/CHANGELOG.md b/core-services/service-request/CHANGELOG.md index d1d5607bbd3..a27826b5875 100644 --- a/core-services/service-request/CHANGELOG.md +++ b/core-services/service-request/CHANGELOG.md @@ -1,9 +1,5 @@ All notable changes to this module will be documented in this file. -## 1.0.1 - 2024-08-29 - -- Added `BOOLEAN` DataType in `AttributeDefinition` - ## 1.0.0 - Base version \ No newline at end of file diff --git a/core-services/service-request/pom.xml b/core-services/service-request/pom.xml index f04bced991b..151055f4c03 100644 --- a/core-services/service-request/pom.xml +++ b/core-services/service-request/pom.xml @@ -4,7 +4,7 @@ service-request jar service-request - 1.0.1 + 1.0.0 1.8 ${java.version} diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java b/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java index e1a99338c3c..c9e5f7b3cb0 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java @@ -31,8 +31,6 @@ public class ErrorCode { public static final String SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG = "Attribute Value provided against the attribute definition of type multi value list must be an instance of list"; - public static final String SERVICE_REQUEST_ATTRIBUTE_INVALID_BOOLEAN_VALUE_MSG = "Attribute Value provided against the attribute definition of type boolean must be an instance of boolean"; - public static final String INVALID_SIZE_OF_INPUT_CODE = "INVALID_SIZE_OF_INPUT_CODE"; public static final String INVALID_SIZE_OF_TEXT_MSG = "Text value cannot be of length greater than configured length "; diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java index 67b2929b36d..66595568bc1 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java @@ -21,7 +21,25 @@ import java.util.Map; import java.util.Set; -import static org.egov.servicerequest.error.ErrorCode.*; +import static org.egov.servicerequest.error.ErrorCode.INVALID_SIZE_OF_INPUT_CODE; +import static org.egov.servicerequest.error.ErrorCode.INVALID_SIZE_OF_TEXT_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_DATETIME_VALUE_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_NUMBER_VALUE_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_SINGLE_VALUE_LIST_VALUE_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_STRING_VALUE_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_TEXT_VALUE_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_MULTIVALUELIST_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_SINGLEVALUELIST_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_VALUES_UNIQUENESS_ERR_CODE; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_VALUES_UNIQUENESS_ERR_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_CODE; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_REQUIRED_ATTRIBUTE_NOT_PROVIDED_ERR_CODE; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_REQUIRED_ATTRIBUTE_NOT_PROVIDED_ERR_MSG; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_UNRECOGNIZED_ATTRIBUTE_CODE; +import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_UNRECOGNIZED_ATTRIBUTE_MSG; @Slf4j @Component @@ -115,10 +133,6 @@ private void validateAttributeValuesAgainstServiceDefinition(ServiceDefinition s if(!(attributeValue.getValue() instanceof List)){ throw new CustomException(SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE, SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG); } - }else if(attributeCodeVsDataType.get(attributeValue.getAttributeCode()).equals(AttributeDefinition.DataTypeEnum.BOOLEAN)){ - if(!(attributeValue.getValue() instanceof Boolean)){ - throw new CustomException(SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE, SERVICE_REQUEST_ATTRIBUTE_INVALID_BOOLEAN_VALUE_MSG); - } } }); diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java index 649421350a1..cefb96adac8 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java @@ -41,7 +41,7 @@ public class AttributeDefinition { @JsonProperty("code") @NotNull - @Size(min = 2, max = 256) + @Size(min = 2, max = 64) private String code = null; /** @@ -50,8 +50,6 @@ public class AttributeDefinition { public enum DataTypeEnum { STRING("String"), - BOOLEAN("Boolean"), - NUMBER("Number"), TEXT("Text"), @@ -112,7 +110,7 @@ public static DataTypeEnum fromValue(String text) { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalFields") + @JsonProperty("additionalDetails") private Object additionalDetails = null; diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java index 98ce105e9b3..8aeff4e39f3 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java @@ -41,7 +41,7 @@ public class AttributeValue { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalFields") + @JsonProperty("additionalDetails") private Object additionalDetails = null; diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java index 4fc646ca8ea..b0348458c15 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java @@ -51,7 +51,7 @@ public class Service { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalFields") + @JsonProperty("additionalDetails") private Object additionalDetails = null; @JsonProperty("accountId") diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java index 01b9b31fac9..e91eeedf541 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java @@ -35,7 +35,7 @@ public class ServiceDefinition { @JsonProperty("code") @NotNull - @Size(min = 2, max = 256) + @Size(min = 2, max = 64) private String code = null; @JsonProperty("isActive") @@ -50,7 +50,7 @@ public class ServiceDefinition { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalFields") + @JsonProperty("additionalDetails") private Object additionalDetails = null; @JsonProperty("clientId") diff --git a/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql b/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql deleted file mode 100644 index ed8ce4007ca..00000000000 --- a/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql +++ /dev/null @@ -1,9 +0,0 @@ --- Migration script to alter the length of 'code' column in both tables to 256 - --- Update eg_service_definition table -ALTER TABLE eg_service_definition -ALTER COLUMN code TYPE character varying(256); - --- Update eg_service_attribute_definition table -ALTER TABLE eg_service_attribute_definition -ALTER COLUMN code TYPE character varying(256); diff --git a/frontend/micro-ui/.gitignore b/frontend/micro-ui/.gitignore new file mode 100644 index 00000000000..feb4cac5c94 --- /dev/null +++ b/frontend/micro-ui/.gitignore @@ -0,0 +1,32 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +.env +.eslintcache + +# yarn $ +.yarn +yarn.lock +.yarnrc.yml + +# dependencies +node_modules +.yarn +/.pnp +.pnp.js + +# testing +/coverage + +# production +/web/build +dist +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/frontend/micro-ui/Jenkinsfile b/frontend/micro-ui/Jenkinsfile new file mode 100644 index 00000000000..1206b9c141d --- /dev/null +++ b/frontend/micro-ui/Jenkinsfile @@ -0,0 +1,3 @@ +library 'ci-libs' + +buildPipeline(configFile: './build/build-config.yml') diff --git a/frontend/micro-ui/README.md b/frontend/micro-ui/README.md new file mode 100644 index 00000000000..9f559d81783 --- /dev/null +++ b/frontend/micro-ui/README.md @@ -0,0 +1,139 @@ + +# DIGIT ui + +A React App built on top of DIGIT UI Core. + +# DIGIT + +DIGIT eGovernance Platform Services + +DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://core.digit.org/ for more details. + +DIGIT platform is microservices based API platform enabling quick rebundling of services as per specific needs. This is a repo that lays down the core platform on top of which other mission services depend. + + +# DIGIT UI + + +This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries. + +Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications + +It is also used to manage the Localisation data present in the system (Localisation service) + + +## Run Locally + +Clone the project + +```bash + git clone https://github.com/egovernments/DIGIT-Frontend.git +``` + +Go to the Sub directory to run UI +```bash + cd into micro-ui/web/micro-ui-internals +``` + +Install dependencies + +```bash + yarn install +``` + +Add .env file +```bash + micro-ui/web/micro-ui-internals/example/.env +``` + +Start the server + +```bash + yarn start +``` + + +## Environment Variables + +To run this project, you will need to add the following environment variables to your .env file + +`REACT_APP_PROXY_API` :: `{{server url}}` + +`REACT_APP_GLOBAL` :: `{{server url}}` + +`REACT_APP_PROXY_ASSETS` :: `{{server url}}` + +`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}` + +`SKIP_PREFLIGHT_CHECK` :: `true` + +[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev) + +## Tech Stack + +**Libraries:** + +[React](https://react.dev/) + +[React Hook Form](https://www.react-hook-form.com/) + +[React Query](https://tanstack.com/query/v3/) + +[Tailwind CSS](https://tailwindcss.com/) + +[Webpack](https://webpack.js.org/) + +## License + +[MIT](https://choosealicense.com/licenses/mit/) + + +## Author + +- [@jagankumar-egov](https://www.github.com/jagankumar-egov) + + +## Documentation + +[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) + + +## Support + +For support, add the issues in https://github.com/egovernments/DIGIT-core/issues. + + +## Modules + + 1. Core + 2. Workbench + 3. HRMS + 4. Dashboard + 5. Engagement + 6. Payment + +## Starting with Digit-UI App (Impelmentation Teams) - MICRO-UI + + +Go to the Sub directory to run UI + +```bash + cd into micro-ui/web +``` + +```bash + yarn install +``` + +Add .env file +```bash + micro-ui/web/.env +``` + +Start the server + +```bash + yarn start +``` + +![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) diff --git a/frontend/micro-ui/package.json b/frontend/micro-ui/package.json new file mode 100644 index 00000000000..78ab4e7aa40 --- /dev/null +++ b/frontend/micro-ui/package.json @@ -0,0 +1,4 @@ +{ + "name": "workbench-ui", + "version": "0.1.0" +} \ No newline at end of file diff --git a/frontend/micro-ui/web/.babelrc b/frontend/micro-ui/web/.babelrc new file mode 100644 index 00000000000..5f90443d15e --- /dev/null +++ b/frontend/micro-ui/web/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "@babel/preset-env","@babel/preset-react" + ] + } \ No newline at end of file diff --git a/frontend/micro-ui/web/.env.sample b/frontend/micro-ui/web/.env.sample new file mode 100644 index 00000000000..e87c7f586c4 --- /dev/null +++ b/frontend/micro-ui/web/.env.sample @@ -0,0 +1,3 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_STATE_LEVEL_TENANT_ID=pb +REACT_APP_PROXY_URL=https://works-dev.digit.org diff --git a/frontend/micro-ui/web/CHANGELOG.md b/frontend/micro-ui/web/CHANGELOG.md new file mode 100644 index 00000000000..826105084e8 --- /dev/null +++ b/frontend/micro-ui/web/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 0.1.0 - 2024-05-28 +#### Base Admin console web + 1. Helps in creating the Campaign and configure delivery rules + 2. Create Data: Validates and creates resource details of type facility,user and boundary. diff --git a/frontend/micro-ui/web/docker/Dockerfile b/frontend/micro-ui/web/docker/Dockerfile new file mode 100644 index 00000000000..8e9b173bb85 --- /dev/null +++ b/frontend/micro-ui/web/docker/Dockerfile @@ -0,0 +1,25 @@ +# FROM egovio/alpine-node-builder-14:yarn AS build +FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build +RUN apk update && apk upgrade +RUN apk add --no-cache git>2.30.0 +ARG WORK_DIR +WORKDIR /app +ENV NODE_OPTIONS "--max-old-space-size=8168" + +COPY ${WORK_DIR} . +RUN ls -lah + +#RUN node web/envs.js +RUN cd web/ \ + && ./install-deps.sh \ + && yarn install \ + && yarn build:webpack + +FROM nginx:mainline-alpine +#FROM ghcr.io/egovernments/nginx:mainline-alpine +ENV WORK_DIR=/var/web/digit-ui + +RUN mkdir -p ${WORK_DIR} + +COPY --from=build /app/web/build ${WORK_DIR}/ +COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/devDockerfile b/frontend/micro-ui/web/docker/devDockerfile new file mode 100644 index 00000000000..d7b1ba1870a --- /dev/null +++ b/frontend/micro-ui/web/docker/devDockerfile @@ -0,0 +1,26 @@ +#FROM egovio/alpine-node-builder-14:yarn AS build +FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build +RUN apk update && apk upgrade +RUN apk add --no-cache git>2.30.0 +ARG WORK_DIR +WORKDIR /app +ENV NODE_OPTIONS "--max-old-space-size=1792" + +COPY ${WORK_DIR} . +RUN ls -lah + +#RUN node web/envs.js +RUN cd web/ \ + && node envs.js \ + && ./install-deps.sh \ + && yarn install \ + && yarn build + +#FROM nginx:mainline-alpine +FROM ghcr.io/egovernments/nginx:mainline-alpine +ENV WORK_DIR=/var/web/digit-ui + +RUN mkdir -p ${WORK_DIR} + +COPY --from=build /app/web/build ${WORK_DIR}/ +COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/masDockerfile b/frontend/micro-ui/web/docker/masDockerfile new file mode 100644 index 00000000000..5d7cf45dd87 --- /dev/null +++ b/frontend/micro-ui/web/docker/masDockerfile @@ -0,0 +1,25 @@ +#FROM egovio/alpine-node-builder-14:yarn AS build +FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build +RUN apk update && apk upgrade +RUN apk add --no-cache git>2.30.0 +ARG WORK_DIR +WORKDIR /app +ENV NODE_OPTIONS "--max-old-space-size=3792" + +COPY ${WORK_DIR} . +RUN ls -lah + +#RUN node web/envs.js +RUN cd web/ \ + && node envs.js \ + && yarn install \ + && yarn build + +#FROM nginx:mainline-alpine +FROM ghcr.io/egovernments/nginx:mainline-alpine +ENV WORK_DIR=/var/web/digit-ui + +RUN mkdir -p ${WORK_DIR} + +COPY --from=build /app/web/build ${WORK_DIR}/ +COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/nginx.conf b/frontend/micro-ui/web/docker/nginx.conf new file mode 100644 index 00000000000..4f532e4a6ed --- /dev/null +++ b/frontend/micro-ui/web/docker/nginx.conf @@ -0,0 +1,12 @@ +server +{ + listen 80; + underscores_in_headers on; + + location /digit-ui + { + root /var/web; + index index.html index.htm; + try_files $uri $uri/ /digit-ui/index.html; + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/envs.js b/frontend/micro-ui/web/envs.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frontend/micro-ui/web/install-deps.sh b/frontend/micro-ui/web/install-deps.sh new file mode 100755 index 00000000000..efaceaee20d --- /dev/null +++ b/frontend/micro-ui/web/install-deps.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +BRANCH="$(git branch --show-current)" + +echo "Main Branch: $BRANCH" + +INTERNALS="micro-ui-internals" + +cp $INTERNALS/example/src/UICustomizations.js src/Customisations + +cd $INTERNALS && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" + + +# yarn install diff --git a/frontend/micro-ui/web/micro-ui-internals/.gitignore b/frontend/micro-ui/web/micro-ui-internals/.gitignore new file mode 100644 index 00000000000..1747c795d6f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/.gitignore @@ -0,0 +1,143 @@ +# Created by https://www.toptal.com/developers/gitignore/api/node,react +# Edit at https://www.toptal.com/developers/gitignore?templates=node,react + +### eGov ### +packages/css/example/index.css +package-lock.json +locales/ +build/ +packages/**/dist/ + +# yarn # +.yarn +.yarnrc.yml + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env*.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist +dist-storybook + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +### react ### +.DS_* +**/*.backup.* +**/*.back.* + +node_modules + +*.sublime* + +psd +thumb +sketch + +# vs code +.vscode/ + +# End of https://www.toptal.com/developers/gitignore/api/node,react \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/.prettierignore b/frontend/micro-ui/web/micro-ui-internals/.prettierignore new file mode 100644 index 00000000000..d54de016ef0 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/.prettierignore @@ -0,0 +1,23 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. +# dependencies +node_modules +# builds +build +dist +.rpt2_cache +# dev +dev.css +index.css +index.compat.css +index.min.css +# misc +.DS_Store +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json b/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json new file mode 100644 index 00000000000..b975008d6f8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "printWidth": 150 +} diff --git a/frontend/micro-ui/web/micro-ui-internals/README.md b/frontend/micro-ui/web/micro-ui-internals/README.md new file mode 100644 index 00000000000..f23a1fcfe9c --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/README.md @@ -0,0 +1,100 @@ + +# workbench ui + +A React App built on top of DIGIT UI Core. + + +# DIGIT UI + +DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://www.digit.org for more details. + +This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries. + +Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications + +It is also used to manage the Localisation data present in the system (Localisation service) + + +## Run Locally + +Clone the project + +```bash + git clone https://github.com/egovernments/Digit-Core.git +``` + +Go to the Sub directory to run UI +```bash + cd into frontend/micro-ui/web/micro-ui-internals +``` + +Install dependencies + +```bash + yarn install +``` + +Add .env file +```bash + frontend/micro-ui/web/micro-ui-internals/example/.env +``` + +Start the server + +```bash + yarn start +``` + + +## Environment Variables + +To run this project, you will need to add the following environment variables to your .env file + +`REACT_APP_PROXY_API` :: `{{server url}}` + +`REACT_APP_GLOBAL` :: `{{server url}}` + +`REACT_APP_PROXY_ASSETS` :: `{{server url}}` + +`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}` + +`SKIP_PREFLIGHT_CHECK` :: `true` + +[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev) + +## Tech Stack + +**Libraries:** + +[React](https://react.dev/) + +[React Hook Form](https://www.react-hook-form.com/) + +[React Query](https://tanstack.com/query/v3/) + +[Tailwind CSS](https://tailwindcss.com/) + +[Webpack](https://webpack.js.org/) + +## License + +[MIT](https://choosealicense.com/licenses/mit/) + + +## Author + +- [@jagankumar-egov](https://www.github.com/jagankumar-egov) + + +## Documentation + +[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) + + +## Support + +For support, add the issues in https://github.com/egovernments/DIGIT-core/issues. + + +![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) + diff --git a/frontend/micro-ui/web/micro-ui-internals/clean.sh b/frontend/micro-ui/web/micro-ui-internals/clean.sh new file mode 100644 index 00000000000..2235ef1c1d0 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/clean.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +BASEDIR="$( cd "$( dirname "$0" )" && pwd )" + +msg() { + echo -e "\n\n\033[32;32m$1\033[0m" +} + +msg "Cleaning root" +rm -rf node_modules + +msg "Cleaning css" +cd "$BASEDIR/packages/css" && rm -rf node_modules + +msg "Cleaning libraries" +cd "$BASEDIR/packages/libraries" && rm -rf node_modules + +msg "Cleaning react-components" +cd "$BASEDIR/packages/react-components" && rm -rf node_modules + +msg "Cleaning PGR module" +cd "$BASEDIR/packages/modules/pgr" && rm -rf node_modules + +msg "Cleaning FSM module" +cd "$BASEDIR/packages/modules/fsm" && rm -rf node_modules + +msg "Cleaning Core module" +cd "$BASEDIR/packages/modules/core" && rm -rf node_modules diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa b/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa new file mode 100644 index 00000000000..73b42b7dfad --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa @@ -0,0 +1,7 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_USER_TYPE=EMPLOYEE +REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a +REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c +REACT_APP_PROXY_API=https://health-qa.digit.org +REACT_APP_PROXY_ASSETS=https://health-qa.digit.org +REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCM.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod new file mode 100644 index 00000000000..2d02707d7eb --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod @@ -0,0 +1,7 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_USER_TYPE=EMPLOYEE +REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a +REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c +REACT_APP_PROXY_API=https://salama.digit.org +REACT_APP_PROXY_ASSETS=https://salama.digit.org +REACT_APP_GLOBAL=https://moz-health-prd.s3.af-south-1.amazonaws.com/globalConfig.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat new file mode 100644 index 00000000000..bedf28a95b1 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat @@ -0,0 +1,7 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_USER_TYPE=EMPLOYEE +REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a +REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c +REACT_APP_PROXY_API=https://moz-health-uat.digit.org +REACT_APP_PROXY_ASSETS=https://moz-health-uat.digit.org +REACT_APP_GLOBAL=https://moz-health-uat.s3.ap-south-1.amazonaws.com/globalConfig.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev b/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev new file mode 100644 index 00000000000..81fd56e040a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev @@ -0,0 +1,9 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_USER_TYPE=EMPLOYEE +REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a +REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c +REACT_APP_PROXY_API=https://unified-dev.digit.org +REACT_APP_PROXY_ASSETS=https://unified-dev.digit.org +REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsMicroplan.js +REACT_APP_CONTEXT=works +WORKBENCH=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCMMZ.js \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/example/package.json b/frontend/micro-ui/web/micro-ui-internals/example/package.json new file mode 100644 index 00000000000..2d8c8857b45 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/package.json @@ -0,0 +1,40 @@ +{ + "name": "@egovernments/digit-ui-example", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "private": true, + "homepage": "digit-ui", + "scripts": { + "start": "react-scripts start" + }, + "devDependencies": { + "@egovernments/digit-ui-libraries": "1.8.2-beta.1", + "@egovernments/digit-ui-module-workbench": "1.0.2-beta.3", + "@egovernments/digit-ui-components": "0.0.2-beta.1", + "@egovernments/digit-ui-module-core": "1.8.2-beta.2", + "@egovernments/digit-ui-module-utilities": "1.0.1-beta.30", + "@egovernments/digit-ui-react-components": "1.8.2-beta.6", + "@egovernments/digit-ui-module-hcmworkbench":"0.0.38", + "@egovernments/digit-ui-module-campaign-manager": "0.0.1", + "@egovernments/digit-ui-module-hcmmicroplanning": "0.0.1", + "http-proxy-middleware": "^1.0.5", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-i18next": "11.16.2", + "react-router-dom": "5.3.0", + "react-scripts": "^4.0.1" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html new file mode 100644 index 00000000000..55ad3b5ca00 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html @@ -0,0 +1,34 @@ + + + + + + + + + DIGIT + + + + + + + + + + + + + + + +
+ + diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js new file mode 100644 index 00000000000..dff584d9ab2 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js @@ -0,0 +1,789 @@ +import { Link } from "react-router-dom"; +import _ from "lodash"; +import { useLocation, useHistory } from "react-router-dom"; +import { useParams } from "react-router-dom"; + +//create functions here based on module name set in mdms(eg->SearchProjectConfig) +//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] +// these functions will act as middlewares +var Digit = window.Digit || {}; + +const businessServiceMap = { + "muster roll": "MR", +}; + +const inboxModuleNameMap = { + "muster-roll-approval": "muster-roll-service", +}; + +function filterUniqueByKey(arr, key) { + const uniqueValues = new Set(); + const result = []; + + arr.forEach((obj) => { + const value = obj[key]; + if (!uniqueValues.has(value)) { + uniqueValues.add(value); + result.push(obj); + } + }); + + return result; +} + +const epochTimeForTomorrow12 = () => { + const now = new Date(); + + // Create a new Date object for tomorrow at 12:00 PM + const tomorrowNoon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 12, 0, 0, 0); + + // Format the date as "YYYY-MM-DD" + const year = tomorrowNoon.getFullYear(); + const month = String(tomorrowNoon.getMonth() + 1).padStart(2, "0"); // Months are 0-indexed + const day = String(tomorrowNoon.getDate()).padStart(2, "0"); + + return Digit.Utils.date.convertDateToEpoch(`${year}-${month}-${day}`); +}; + +function cleanObject(obj) { + for (const key in obj) { + if (Object.hasOwn(obj, key)) { + if (Array.isArray(obj[key])) { + if (obj[key].length === 0) { + delete obj[key]; + } + } else if ( + obj[key] === undefined || + obj[key] === null || + obj[key] === false || + obj[key] === "" || // Check for empty string + (typeof obj[key] === "object" && Object.keys(obj[key]).length === 0) + ) { + delete obj[key]; + } + } + } + return obj; +} + +export const UICustomizations = { + businessServiceMap, + updatePayload: (applicationDetails, data, action, businessService) => { + if (businessService === businessServiceMap.estimate) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + estimate: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap.contract) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + contract: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["muster roll"]) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + musterRoll: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["works.purchase"]) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + const additionalFieldsToSet = { + projectId: applicationDetails.additionalDetails.projectId, + invoiceDate: applicationDetails.billDate, + invoiceNumber: applicationDetails.referenceId.split("_")?.[1], + contractNumber: applicationDetails.referenceId.split("_")?.[0], + documents: applicationDetails.additionalDetails.documents, + }; + return { + bill: { ...applicationDetails, ...additionalFieldsToSet }, + workflow, + }; + } + }, + enableModalSubmit: (businessService, action, setModalSubmit, data) => { + if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") { + setModalSubmit(data?.acceptTerms); + } + }, + enableHrmsSearch: (businessService, action) => { + if (businessService === businessServiceMap.estimate) { + return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); + } + if (businessService === businessServiceMap.contract) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + if (businessService === businessServiceMap?.["muster roll"]) { + return action.action.includes("VERIFY"); + } + if (businessService === businessServiceMap?.["works.purchase"]) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + return false; + }, + getBusinessService: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return businessServiceMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return businessServiceMap?.contract; + } else if (moduleCode?.includes("muster roll")) { + return businessServiceMap?.["muster roll"]; + } else if (moduleCode?.includes("works.purchase")) { + return businessServiceMap?.["works.purchase"]; + } else if (moduleCode?.includes("works.wages")) { + return businessServiceMap?.["works.wages"]; + } else if (moduleCode?.includes("works.supervision")) { + return businessServiceMap?.["works.supervision"]; + } else { + return businessServiceMap; + } + }, + getInboxModuleName: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return inboxModuleNameMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return inboxModuleNameMap?.contracts; + } else if (moduleCode?.includes("attendence")) { + return inboxModuleNameMap?.attendencemgmt; + } else { + return inboxModuleNameMap; + } + }, + + AttendanceInboxConfig: { + preProcess: (data) => { + //set tenantId + data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId(); + data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + + const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim(); + if (musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber; + + const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim(); + if (attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName; + + // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side) + const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee); + delete data.body.inbox.moduleSearchCriteria.assignee; + if (assignee?.code === "ASSIGNED_TO_ME") { + data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid; + } + + //cloning locality and workflow states to format them + // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []); + + let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null); + delete data.body.inbox.moduleSearchCriteria.orgId; + if (selectedOrg) { + data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber; + } + + // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null); + // delete data.body.inbox.moduleSearchCriteria.ward; + // if(selectedWard) { + // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code; + // } + + let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []); + let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []); + // delete data.body.inbox.moduleSearchCriteria.locality; + delete data.body.inbox.moduleSearchCriteria.state; + delete data.body.inbox.moduleSearchCriteria.ward; + + // locality = locality?.map((row) => row?.code); + states = Object.keys(states)?.filter((key) => states[key]); + ward = ward?.map((row) => row?.code); + + // //adding formatted data to these keys + // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality; + if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states; + if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward; + const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {}); + if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code; + + //adding tenantId to moduleSearchCriteria + data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + + //setting limit and offset becoz somehow they are not getting set in muster inbox + data.body.inbox.limit = data.state.tableForm.limit; + data.body.inbox.offset = data.state.tableForm.offset; + delete data.state; + return data; + }, + postProcess: (responseArray, uiConfig) => { + const statusOptions = responseArray?.statusMap + ?.filter((item) => item.applicationstatus) + ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` })); + if (uiConfig?.type === "filter") { + let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus"); + if (fieldConfig.length) { + fieldConfig[0].populators.options = statusOptions; + } + } + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "ATM_MUSTER_ROLL_ID") { + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + } + if (key === "ATM_ATTENDANCE_WEEK") { + const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate( + value?.endDate, + "dd/MM/yyyy" + )}`; + return
{week}
; + } + if (key === "ATM_NO_OF_INDIVIDUALS") { + return
{value?.length}
; + } + if (key === "ATM_AMOUNT_IN_RS") { + return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")}; + } + if (key === "ATM_SLA") { + return parseInt(value) > 0 ? ( + {t(value) || ""} + ) : ( + {t(value) || ""} + ); + } + if (key === "COMMON_WORKFLOW_STATES") { + return {t(`WF_MUSTOR_${value}`)}; + } + //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default + return {t(`CASE_NOT_HANDLED`)}; + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "ATM_MUSTER_ROLL_ID") + link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`; + }); + return link; + }, + populateReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + return { + url: "/org-services/organisation/v1/_search", + params: { limit: 50, offset: 0 }, + body: { + SearchCriteria: { + tenantId: tenantId, + functions: { + type: "CBO", + }, + }, + }, + config: { + enabled: true, + select: (data) => { + return data?.organisations; + }, + }, + }; + }, + }, + SearchWageSeekerConfig: { + customValidationCheck: (data) => { + //checking both to and from date are present + const { createdFrom, createdTo } = data; + if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) + return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + + return false; + }, + preProcess: (data) => { + data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() }; + + let requestBody = { ...data.body.Individual }; + const pathConfig = { + name: "name.givenName", + }; + const dateConfig = { + createdFrom: "daystart", + createdTo: "dayend", + }; + const selectConfig = { + wardCode: "wardCode[0].code", + socialCategory: "socialCategory.code", + }; + const textConfig = ["name", "individualId"]; + let Individual = Object.keys(requestBody) + .map((key) => { + if (selectConfig[key]) { + requestBody[key] = _.get(requestBody, selectConfig[key], null); + } else if (typeof requestBody[key] == "object") { + requestBody[key] = requestBody[key]?.code; + } else if (textConfig?.includes(key)) { + requestBody[key] = requestBody[key]?.trim(); + } + return key; + }) + .filter((key) => requestBody[key]) + .reduce((acc, curr) => { + if (pathConfig[curr]) { + _.set(acc, pathConfig[curr], requestBody[curr]); + } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { + _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); + } else { + _.set(acc, curr, requestBody[curr]); + } + return acc; + }, {}); + + data.body.Individual = { ...Individual }; + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + //here we can add multiple conditions + //like if a cell is link then we return link + //first we can identify which column it belongs to then we can return relevant result + switch (key) { + case "MASTERS_WAGESEEKER_ID": + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + + case "MASTERS_SOCIAL_CATEGORY": + return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); + + case "CORE_COMMON_PROFILE_CITY": + return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); + + case "MASTERS_WARD": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + + case "MASTERS_LOCALITY": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + default: + return t("ES_COMMON_NA"); + } + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "MASTERS_WAGESEEKER_ID") + link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; + }); + return link; + }, + additionalValidations: (type, data, keys) => { + if (type === "date") { + return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; + } + }, + }, + SearchDefaultConfig: { + customValidationCheck: (data) => { + //checking both to and from date are present + const { createdFrom, createdTo } = data; + if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) + return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + + return false; + }, + preProcess: (data) => { + const location = useLocation(); + data.params = { ...data.params }; + const { masterName } = useParams(); + + const searchParams = new URLSearchParams(location.search); + const paths = { + SearchProjectConfig: { + basePath: "Projects", + pathConfig: { + // id: "id[0]", + tenantId: "tenantId", + }, + dateConfig: { + endDate: "dayend", + startDate: "daystart", + }, + selectConfig: {}, + textConfig: ["id", "tenantId", "name", "projectNumber", "projectSubType", "projectType"], + }, + SearchProductConfig: { + basePath: "Product", + pathConfig: { + id: "id[0]", + }, + dateConfig: {}, + selectConfig: {}, + textConfig: ["id", "manufacturer", "name", "type"], + }, + SearchHouseholdConfig: { + basePath: "Household", + pathConfig: { + id: "id[0]", + clientReferenceId: "clientReferenceId[0]", + }, + dateConfig: {}, + selectConfig: {}, + textConfig: ["boundaryCode", "clientReferenceId", "id"], + }, + SearchProductVariantConfig: { + basePath: "ProductVariant", + pathConfig: { + id: "id[0]", + }, + dateConfig: {}, + selectConfig: {}, + textConfig: ["productId", "sku", "variation"], + }, + SearchProjectBeneficiaryConfig: { + basePath: "ProjectBeneficiary", + pathConfig: { + id: "id[0]", + clientReferenceId: "clientReferenceId[0]", + }, + dateConfig: { + dateOfRegistration: "daystart", + }, + selectConfig: {}, + textConfig: ["beneficiaryId", "projectId"], + }, + SearchProjectStaffConfig: { + basePath: "ProjectStaff", + pathConfig: { + id: "id[0]", + }, + dateConfig: { + startDate: "daystart", + endDate: "dayend", + }, + selectConfig: {}, + textConfig: ["projectId", "userId"], + }, + SearchProjectResourceConfig: { + basePath: "ProjectResource", + pathConfig: { + id: "id[0]", + }, + dateConfig: {}, + selectConfig: {}, + textConfig: [], + }, + SearchProjectTaskConfig: { + basePath: "Task", + pathConfig: { + id: "id[0]", + clientReferenceId: "clientReferenceId[0]", + }, + dateConfig: { + plannedEndDate: "dayend", + plannedStartDate: "daystart", + actualEndDate: "dayend", + actualStartDate: "daystart", + }, + selectConfig: {}, + textConfig: ["projectId", "localityCode", "projectBeneficiaryId", "status"], + }, + SearchFacilityConfig: { + basePath: "Facility", + pathConfig: { + id: "id[0]", + }, + dateConfig: {}, + selectConfig: {}, + textConfig: ["faciltyUsage", "localityCode", "storageCapacity", "id"], + }, + SearchProjectFacilityConfig: { + basePath: "ProjectFacility", + pathConfig: { + id: "id[0]", + projectId: "projectId[0]", + facilityId: "facilityId[0]", + }, + dateConfig: {}, + selectConfig: {}, + textConfig: [], + }, + }; + + const id = searchParams.get("config") || masterName; + + if (!paths || !paths?.[id]) { + return data; + } + let requestBody = { ...data.body[paths[id]?.basePath] }; + const pathConfig = paths[id]?.pathConfig; + const dateConfig = paths[id]?.dateConfig; + const selectConfig = paths[id]?.selectConfig; + const textConfig = paths[id]?.textConfig; + + if (paths[id].basePath == "Projects") { + data.state.searchForm = { ...data.state.searchForm, tenantId: "mz" }; + } + let Product = Object.keys(requestBody) + .map((key) => { + if (selectConfig[key]) { + requestBody[key] = _.get(requestBody, selectConfig[key], null); + } else if (typeof requestBody[key] == "object") { + requestBody[key] = requestBody[key]?.code; + } else if (textConfig?.includes(key)) { + requestBody[key] = requestBody[key]?.trim(); + } + return key; + }) + .filter((key) => requestBody[key]) + .reduce((acc, curr) => { + if (pathConfig[curr]) { + _.set(acc, pathConfig[curr], requestBody[curr]); + } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { + _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); + } else { + _.set(acc, curr, requestBody[curr]); + } + return acc; + }, {}); + + if (paths[id].basePath == "Projects") { + data.body[paths[id].basePath] = [{ ...Product }]; + } else data.body[paths[id].basePath] = { ...Product }; + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + //here we can add multiple conditions + //like if a cell is link then we return link + //first we can identify which column it belongs to then we can return relevant result + switch (key) { + case "ID": + return ( + + + + ); + + case "MASTERS_SOCIAL_CATEGORY": + return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); + + case "CORE_COMMON_PROFILE_CITY": + return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); + + case "MASTERS_WARD": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + + case "MASTERS_LOCALITY": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + default: + return t("ES_COMMON_NA"); + } + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "MASTERS_WAGESEEKER_ID") + link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; + }); + return link; + }, + additionalValidations: (type, data, keys) => { + if (type === "date") { + return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; + } + }, + }, + SearchCampaign: { + preProcess: (data, additionalDetails) => { + const { campaignName = "", endDate = "", projectType = "", startDate = "" } = data?.state?.searchForm || {}; + data.body.CampaignDetails = {}; + data.body.CampaignDetails.pagination = data?.state?.tableForm; + data.body.CampaignDetails.tenantId = Digit.ULBService.getCurrentTenantId(); + // data.body.CampaignDetails.boundaryCode = boundaryCode; + data.body.CampaignDetails.createdBy = Digit.UserService.getUser().info.uuid; + data.body.CampaignDetails.campaignName = campaignName; + data.body.CampaignDetails.status = ["drafted"]; + if (startDate) { + data.body.CampaignDetails.startDate = Digit.Utils.date.convertDateToEpoch(startDate); + } else { + data.body.CampaignDetails.startDate = epochTimeForTomorrow12(); + } + if (endDate) { + data.body.CampaignDetails.endDate = Digit.Utils.date.convertDateToEpoch(endDate); + } + data.body.CampaignDetails.projectType = projectType?.[0]?.code; + + cleanObject(data.body.CampaignDetails); + + return data; + }, + populateProjectType: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + + return { + url: "/egov-mdms-service/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId, + moduleDetails: [ + { + moduleName: "HCM-PROJECT-TYPES", + masterDetails: [ + { + name: "projectTypes", + }, + ], + }, + ], + }, + }, + changeQueryName: "projectType", + config: { + enabled: true, + select: (data) => { + const dropdownData = filterUniqueByKey(data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes, "code").map((row) => { + return { + ...row, + i18nKey: Digit.Utils.locale.getTransformedLocale(`CAMPAIGN_TYPE_${row.code}`), + }; + }); + return dropdownData; + }, + }, + }; + }, + customValidationCheck: (data) => { + //checking if both to and from date are present then they should be startDate<=endDate + const { startDate, endDate } = data; + const startDateEpoch = Digit.Utils.date.convertDateToEpoch(startDate); + const endDateEpoch = Digit.Utils.date.convertDateToEpoch(endDate); + + if (startDate && endDate && startDateEpoch > endDateEpoch) { + return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + } + return false; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "CAMPAIGN_DATE") { + return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.endDate)}`; + } + }, + }, + SearchMicroplan: { + preProcess: (data, additionalDetails) => { + const { name, status } = data?.state?.searchForm || {}; + + data.body.PlanConfigurationSearchCriteria = {}; + data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit; + // data.body.PlanConfigurationSearchCriteria.limit = 10 + data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset; + data.body.PlanConfigurationSearchCriteria.name = name; + data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid; + // delete data.body.PlanConfigurationSearchCriteria.pagination + data.body.PlanConfigurationSearchCriteria.status = status?.status; + cleanObject(data.body.PlanConfigurationSearchCriteria); + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "CAMPAIGN_DATE") { + return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.CampaignDetails?.endDate)}`; + } + }, + }, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/index.js b/frontend/micro-ui/web/micro-ui-internals/example/src/index.js new file mode 100644 index 00000000000..c186da539bd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/index.js @@ -0,0 +1,84 @@ +import React from "react"; +import ReactDOM from "react-dom"; + +import { initLibraries } from "@egovernments/digit-ui-libraries"; +// import { paymentConfigs, PaymentLinks, PaymentModule } from "@egovernments/digit-ui-module-common"; +import { DigitUI } from "@egovernments/digit-ui-module-core"; +import "@egovernments/digit-ui-css/example/index.css"; + +import { UICustomizations } from "./UICustomizations"; +import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager" +import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; +import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; +import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; +import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; + +var Digit = window.Digit || {}; + +const enabledModules = [ + "DSS", + "HRMS", + "Workbench", + "HCMWORKBENCH", + "Campaign", + // "Engagement", "NDSS","QuickPayLinks", "Payment", + "Utilities", + "Microplanning" + //added to check fsm + // "FSM" +]; + +const initTokens = (stateCode) => { + const userType = window.sessionStorage.getItem("userType") || process.env.REACT_APP_USER_TYPE || "CITIZEN"; + const token = window.localStorage.getItem("token") || process.env[`REACT_APP_${userType}_TOKEN`]; + + const citizenInfo = window.localStorage.getItem("Citizen.user-info"); + + const citizenTenantId = window.localStorage.getItem("Citizen.tenant-id") || stateCode; + + const employeeInfo = window.localStorage.getItem("Employee.user-info"); + const employeeTenantId = window.localStorage.getItem("Employee.tenant-id"); + + const userTypeInfo = userType === "CITIZEN" || userType === "QACT" ? "citizen" : "employee"; + window.Digit.SessionStorage.set("user_type", userTypeInfo); + window.Digit.SessionStorage.set("userType", userTypeInfo); + + if (userType !== "CITIZEN") { + window.Digit.SessionStorage.set("User", { access_token: token, info: userType !== "CITIZEN" ? JSON.parse(employeeInfo) : citizenInfo }); + } else { + // if (!window.Digit.SessionStorage.get("User")?.extraRoleInfo) window.Digit.SessionStorage.set("User", { access_token: token, info: citizenInfo }); + } + + window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); + + if (employeeTenantId && employeeTenantId.length) window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); +}; + +const initDigitUI = () => { + window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH") || "digit-ui"; + window.Digit.Customizations = { + commonUiConfig: UICustomizations + }; + window?.Digit.ComponentRegistryService.setupRegistry({ + // PaymentModule, + // ...paymentConfigs, + // PaymentLinks, + }); + initUtilitiesComponents(); + initWorkbenchComponents(); + initWorkbenchHCMComponents(); + initCampaignComponents(); + initMicroplanningComponents(); + + const moduleReducers = (initData) => initData; + + + const stateCode = window?.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || "pb"; + initTokens(stateCode); + + ReactDOM.render(, document.getElementById("root")); +}; + +initLibraries().then(() => { + initDigitUI(); +}); diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js b/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js new file mode 100644 index 00000000000..9fbb1258ba9 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js @@ -0,0 +1,101 @@ +const { createProxyMiddleware } = require("http-proxy-middleware"); + +const createProxy = createProxyMiddleware({ + //target: process.env.REACT_APP_PROXY_API || "https://uat.digit.org", + // target: process.env.REACT_APP_PROXY_API || "https://qa.digit.org", + target: process.env.REACT_APP_PROXY_API || "https://works-dev.digit.org", + changeOrigin: true, + secure: false, +}); +const assetsProxy = createProxyMiddleware({ + target: process.env.REACT_APP_PROXY_ASSETS || "https://works-dev.digit.org", + changeOrigin: true, + secure: false, +}); +const mdmsProxy = createProxyMiddleware({ + target: process.env.REACT_APP_PROXY_ASSETS || "http://localhost:8080", + changeOrigin: true, + secure: false, +}); +module.exports = function (app) { + ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); + [ + "/access/v1/actions/mdms", + "/egov-mdms-service", + "/mdms-v2", + "/egov-idgen", + "/egov-location", + "/localization", + "/egov-workflow-v2", + "/pgr-services", + "/filestore", + "/egov-hrms", + "/user-otp", + "/user", + "/fsm", + "/billing-service", + "/collection-services", + "/pdf-service", + "/pg-service", + "/vehicle", + "/vendor", + "/property-services", + "/fsm-calculator/v1/billingSlab/_search", + "/pt-calculator-v2", + "/dashboard-analytics", + "/echallan-services", + "/egov-searcher/bill-genie/mcollectbills/_get", + "/egov-searcher/bill-genie/billswithaddranduser/_get", + "/egov-searcher/bill-genie/waterbills/_get", + "/egov-searcher/bill-genie/seweragebills/_get", + "/egov-pdf/download/UC/mcollect-challan", + "/egov-hrms/employees/_count", + "/tl-services/v1/_create", + "/tl-services/v1/_search", + "/egov-url-shortening/shortener", + "/inbox/v1/_search", + "/inbox/v2/_search", + "/tl-services", + "/tl-calculator", + "/org-services", + "/edcr", + "/bpa-services", + "/noc-services", + "/egov-user-event", + "/egov-document-uploader", + "/egov-pdf", + "/egov-survey-services", + "/ws-services", + "/sw-services", + "/ws-calculator", + "/sw-calculator/", + "/egov-searcher", + "/report", + "/inbox/v1/dss/_search", + "/loi-service", + "/project/v1/", + "/estimate-service", + "/loi-service", + "/works-inbox-service/v2/_search", + "/egov-pdf/download/WORKSESTIMATE/estimatepdf", + "/muster-roll", + "/individual", + "/mdms-v2", + "/hcm-moz-impl", + "/project", + "/project/staff/v1/_search", + "/project/v1/_search", + "/facility/v1/_search", + "/product/v1/_search", + "/product/variant/v1/_search", + "/hcm-bff/bulk/_transform", + "/hcm-bff/hcm/_processmicroplan", + "/health-hrms", + "/project-factory", + "/boundary-service", + "/product", + "/plan-service", + ].forEach((location) => app.use(location, createProxy)); + ["/pb-egov-assets"].forEach((location) => app.use(location, assetsProxy)); + ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/package.json b/frontend/micro-ui/web/micro-ui-internals/package.json new file mode 100644 index 00000000000..d15c627d3ab --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/package.json @@ -0,0 +1,59 @@ +{ + "name": "egovernments", + "version": "1.0.0", + "main": "index.js", + "workspaces": [ + "example", + "packages/css", + "packages/modules/*" + ], + "author": "JaganKumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "scripts": { + "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", + "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", + "start:dev": "run-p dev:**", + "start:script": "./scripts/create.sh", + "dev:css": "cd packages/css && yarn start", + "publish:css": "cd packages/css && yarn && npm publish --tag workbench-1.0", + "dev:example": "cd example && yarn start", + "dev:campaign": "cd packages/modules/campaign-manager && yarn start", + "dev:hcmmicroplan": "cd packages/modules/hcm-microplanning && yarn start", + "build": "run-p build:**", + "build:campaign": "cd packages/modules/campaign-manager && yarn build", + "build:hcmmicroplan": "cd packages/modules/hcm-microplanning && yarn build", + "deploy:jenkins": "./scripts/jenkins.sh", + "clean": "rm -rf node_modules" + }, + "resolutions": { + "**/@babel/runtime": "7.20.1", + "**/babel-preset-react-app": "10.0.0" + }, + "devDependencies": { + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "husky": {}, + "lint-staged": { + "*.{js,css,md}": "prettier --write" + }, + "dependencies": { + "ajv": "8.12.0", + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "@egovernments/digit-ui-react-components": "1.8.2-beta.6", + "@egovernments/digit-ui-components": "0.0.2-beta.1", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0" + } +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md b/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md new file mode 100644 index 00000000000..6efe08ae5c5 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md @@ -0,0 +1,62 @@ + + +# digit-ui-css + +## Install + +```bash +npm install --save @egovernments/digit-ui-css +``` + +## Limitation + +```bash +This Package is more specific to DIGIT-UI's can be used across mission's +It is the base css for all Digit UI's +``` + +## Usage + +After adding the dependency make sure you have this dependency in + +```bash +frontend/micro-ui/web/package.json +``` + +```json +"@egovernments/digit-ui-css":"^1.5.0", +``` + +then navigate to App.js + +```bash +frontend/micro-ui/web/public/index.html +``` + +```jsx +/** add this import **/ + + + +``` +### Changelog + +```bash +1.0.7-campaign some css fixes in attribute +1.0.5-campaign some css fixes in previous button +1.0.4-campaign updated styling for create campaign screens +1.0.2-campaign update Styling added for delivery rule screen +1.0.1-campaign Styling added for delivery rule screen +1.0.0-campaign Base version + +``` +## Contributors + +[jagankumar-egov] [nipunarora-eGov] + +### Published from DIGIT Frontend +DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/develop) + +## License + +MIT © [jagankumar-egov](https://github.com/jagankumar-egov) diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js new file mode 100644 index 00000000000..5d1a705494a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js @@ -0,0 +1,71 @@ +const fs = require("fs"); +const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync("package.json")); + +const headerString = ` +@charset "UTF-8"; +/*! + * ${name} - ${version} + * + * Copyright (c) ${new Date().getFullYear()} ${author} + * + */ + `; +const { series, src, dest, watch, task } = require("gulp"); +const header = require("postcss-header"); + +const clean = require("gulp-clean"); +const postcss = require("gulp-postcss"); +const sass = require('gulp-sass'); + +const postcssPresetEnv = require("postcss-preset-env"); +const cleanCSS = require("gulp-clean-css"); +const rename = require("gulp-rename"); +const livereload = require("gulp-livereload"); + +let output = "./example"; +if (process.env.NODE_ENV === "production") { + output = "./dist"; +} + +function cleanStyles() { + return src(`${output}/*.css`, { read: false }).pipe(clean()); +} + +function styles() { + const plugins = [ + require("postcss-import"), + require("tailwindcss"), + postcssPresetEnv({ stage: 2, autoprefixer: { cascade: false }, features: { "custom-properties": true } }), + require("autoprefixer"), + require("cssnano"), + header({ header: headerString }), + ]; + return src("src/index.scss").pipe(postcss(plugins)).pipe(sass()).pipe(dest(output)); +} + +function minify() { + return src(`${output}/index.css`).pipe(cleanCSS()).pipe(rename(`index.min.css`)).pipe(dest(output)); +} + +function stylesLive() { + styles().pipe(livereload({ start: true })); +} + +function livereloadStyles() { + livereload.listen(); + watch("src/**/*.scss", series(stylesLive)); +} + +exports.styles = styles; +exports.default = series(styles); +exports.watch = livereloadStyles; +if (process.env.NODE_ENV === "production") { + exports.build = series(cleanStyles, styles, minify); +} else { + exports.build = series(styles, livereloadStyles); +} + +// gulp.task("watch:styles", function () { +// livereload.listen(); +// gulp.watch("**/*.scss", ["styles"]); +// }); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json new file mode 100644 index 00000000000..5f503a9ebf5 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json @@ -0,0 +1,65 @@ +{ + "name": "@egovernments/digit-ui-css", + "version": "1.0.56-campaign", + "license": "MIT", + "main": "dist/index.css", + "author": "Jagankumar ", + "engines": { + "node": ">=14" + }, + "cssConfig": { + "prefix": "" + }, + "scripts": { + "start": "gulp build", + "build:prod": "NODE_ENV=production gulp build", + "prepublish": "yarn build:prod", + "deploy": "gulp && cp -R svg example && cp -R img example && gh-pages -d example" + }, + "browserslist": [ + "> 3%", + "last 2 versions" + ], + "style": "./dist/index.css", + "dependencies": { + "node-sass": "4.14.1", + "normalize.css": "8.0.1", + "postcss-scss": "3.0.5", + "tailwindcss": "1.9.6" + }, + "devDependencies": { + "autoprefixer": "10.4.14", + "cssnano": "4.1.11", + "gh-pages": "3.2.3", + "gulp": "4.0.2", + "gulp-clean": "0.4.0", + "gulp-clean-css": "4.3.0", + "gulp-livereload": "4.0.2", + "gulp-postcss": "9.0.1", + "gulp-rename": "2.0.0", + "gulp-sass": "4.1.1", + "postcss": "8.4.26", + "postcss-cli": "8.3.1", + "postcss-header": "2.0.0", + "postcss-import": "12.0.1", + "postcss-prefixer": "2.1.3", + "postcss-preset-env": "6.7.1", + "postcss-scss": "3.0.5", + "sass": "^1.26.11" + }, + "files": [ + "dist/index.min.css", + "dist/index.css", + "svg/**/*.svg", + "img/**/*.png", + "src/**/*.scss", + "src/**/*.css" + ], + "keywords": [ + "digit", + "egov", + "dpg", + "digit-ui", + "css" + ] +} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js new file mode 100644 index 00000000000..18485de221e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js @@ -0,0 +1,55 @@ +const postcssPresetEnv = require("postcss-preset-env"); + +module.exports = { + parser: require("postcss-scss"), + plugins: [ + require("postcss-import"), + require("postcss-nested").default, + require("tailwindcss"), + require("postcss-preset-env"), + require("autoprefixer"), + // require("cssnano"), + ], +}; + +// const fs = require('fs'); +// const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync('package.json')); + +// const header = ` +// @charset "UTF-8"; +// /*! +// * ${name} - ${version} +// * +// * Copyright (c) ${new Date().getFullYear()} ${author.name} +// */ +// `; + +// module.exports = (ctx) => { +// const prefix = ctx.env === 'compat' ? '' : cssConfig.prefix; +// const devMessage = `🎉🎉🎉🎉 \n${name} ${ctx.env} build was compiled sucessfully! \n`; + + +// return { +// map: ctx.options.map, +// parser: ctx.options.parser, +// plugins: { +// 'postcss-import': { root: ctx.file.dirname }, +// 'postcss-prefixer': { +// prefix, +// ignore: [/\[class\*=.*\]/], +// }, +// 'postcss-preset-env': { +// autoprefixer: { +// cascade: false, +// }, +// features: { +// 'custom-properties': true, +// }, +// }, +// cssnano: ctx.env === 'production' || ctx.env === 'compat' ? {} : false, +// 'postcss-header': { +// header, +// }, +// }, +// }; +// }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss new file mode 100644 index 00000000000..f01756f1e7d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss @@ -0,0 +1,363 @@ +.microplanning { + .upload { + display: flex; + width: 100%; + justify-content: space-between; + margin-top: 1.25rem; + } + + .upload-section-option { + width: 12.5rem; + min-height: 32rem; + background-color: #ffffff; + border-top-left-radius: 0.5rem; + border-bottom-left-radius: 0.5rem; + padding: 0.625rem; + box-shadow: 0px 1px 2px 0px #00000029; + } + + .upload-section-options-active { + min-height: 3.7rem; + display: flex; + align-items: center; + border-bottom: 1px rgba(214, 213, 212, 1) solid; + cursor: pointer; + border-right: 0.3rem solid rgba(244, 119, 56, 1); + background-color: rgba(244, 119, 56, 0.12); + + p { + color: rgba(80, 90, 95, 1); + font-weight: 400; + font-size: 16px; + } + } + + .upload-section-options-inactive { + min-height: 3.7rem; + display: flex; + align-items: center; + border-bottom: 1px rgba(214, 213, 212, 1) solid; + cursor: pointer; + border-right: none; + background-color: rgba(255, 255, 255, 1); + + p { + color: rgba(80, 90, 95, 1); + font-weight: 400; + font-size: 16px; + } + } + + .upload-component { + width: 80%; + height: min-content; + border-radius: 0.25rem; + padding: 1.5rem; + background-color: rgba(255, 255, 255, 1); + margin: 0; + margin-right: 0.3rem; + padding-bottom: 0.625rem; + } + + .upload-component-active { + display: flex; + flex-direction: column; + margin-bottom: 0; + + .greyedout-name { + color: rgba(177, 180, 182, 1); + margin: 0 0.625rem; + font-size: 1.25rem; + padding-top: 0px; + font-weight: 500; + } + + h2 { + margin-top: 0.625rem; + font-size: 2.5rem; + margin: 0.625rem 0; + font-weight: 700; + } + + p { + margin: 0.625rem 0; + padding-top: 0.625; + font-size: 1rem; + margin-top: 0.625rem; + font-weight: 400; + } + } + + .upload-component-inactive { + display: none; + } + + .upload-option-container { + display: flex; + align-items: center; + justify-content: center; + padding: 1.25rem 0; + flex-wrap: wrap; + + .upload-option-container-selected { + border: 2px rgba(244, 119, 56, 1) solid; + color: rgba(244, 119, 56, 1); + } + } + + .upload-option { + border-radius: 0.25rem; + border: 0.0625rem rgba(214, 213, 212, 1) solid; + min-width: 12.5rem; + min-height: 8.75rem; + box-shadow: 0 0.0625rem rgba(0, 0, 0, 0.16); + padding: 0.625rem 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + justify-items: center; + margin: 0 1.25rem; + cursor: pointer; + + &:hover { + border: 2px rgba(244, 119, 56, 1) solid; + } + + p { + margin-top: 0.625rem; + } + + .upload-option-selected { + border: 0.125rem rgba(244, 119, 56, 1) solid; + color: rgba(244, 119, 56, 1); + } + + .select-button { + justify-self: end; + border: 1px solid rgba(244, 119, 56, 1); + background-color: rgba(255, 255, 255, 1); + width: 11rem; + height: 2.5rem; + padding: 0.6rem 0.5rem; + color: rgba(244, 119, 56, 1); + font-size: 1rem; + font-weight: 600; + } + + .selected-button { + justify-self: end; + border: 1px solid rgba(244, 119, 56, 1); + background-color: rgba(244, 119, 56, 1); + width: 11rem; + height: 2.5rem; + padding: 0.6rem 0.5rem; + color: rgb(255, 255, 255); + font-size: 1rem; + font-weight: 600; + } + } + + .modal-header { + width: 30rem; + font-weight: 700; + font-size: 1.5rem; + padding-left: 1rem; + margin-bottom: 0; + display: flex; + flex-wrap: wrap; + overflow: hidden; + } + + .modal-body { + overflow: hidden; + padding-left: 1rem; + padding-right: 1rem; + margin-bottom: 1rem; + margin-right: 1rem; + + p { + font-weight: 400; + font-size: 1rem; + } + } + + .upload-file { + min-width: 90%; + min-height: 10rem; + padding-top: 0.625; + border: 1px rgba(214, 213, 212, 1) dotted; + margin: 1rem 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: rgba(250, 250, 250, 255); + } + + .uploaded-file { + border: 1px solid rgba(214, 213, 212, 1); + min-height: 4.75rem; + background-color: rgb(256, 252, 252); + display: flex !important; + flex-direction: row; + justify-content: space-between; + align-items: center; + margin-top: 0.625rem; + padding: 0 0.625rem; + flex-wrap: wrap; + + .uploaded-file-details { + display: flex; + flex-direction: row; + align-items: center; + flex-wrap: wrap; + padding: 1rem 0; + + p { + padding: 0; + margin: 0; + height: min-content; + font-weight: 700; + font-size: 1.5rem; + color: rgba(80, 90, 95, 1); + text-align: start; + } + } + + .uploaded-file-operations { + display: flex !important; + flex-direction: row; + align-items: center; + justify-items: end; + flex-wrap: wrap; + .button { + display: flex !important; + flex-direction: row; + align-items: center !important; + justify-content: center; + margin-left: 1rem; + min-width: 9rem; + height: 2.5rem; + border: 1px rgba(244, 119, 56, 1) solid; + background-color: white; + cursor: pointer; + } + + p { + padding: 0; + margin: 0; + color: rgba(244, 119, 56, 1); + font-weight: 600; + font-size: 1rem; + } + + .deletebutton { + background-color: rgb(255, 255, 255, 0); + border: none; + } + } + } + + .loader-container { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + background-color: rgba(0, 0, 0, 0.7); + position: fixed; + top: 0; + left: 0; + z-index: 99999; + + .loader { + border: 0.5rem solid rgb(255, 255, 255); + border-top: 0.5rem solid rgba(80, 76, 76, 0); + border-radius: 50%; + width: 3.125rem; + height: 3.125rem; + animation: spin 2s linear infinite; + } + + .loader-inner { + border: 1px solid rgb(255, 255, 255); + border-radius: 50%; + width: 100%; + height: 100%; + } + + .loader-text { + color: whitesmoke; + padding-top: 1.25rem; + } + } + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } + + .toast-container { + position: fixed; + width: 50%; + bottom: 1.25rem; + left: 50%; + transform: translateX(-50%); + color: #fff; + padding: 1rem; + z-index: 9999; + } + + .success { + background-color: rgba(0, 112, 60, 1); + } + + .toast-content { + display: flex; + align-items: center; + justify-content: space-between; + } + + .message { + margin-right: 0.6px; + } + + .close-button { + background: transparent; + border: none; + color: inherit; + cursor: pointer; + } + + .altrady-have-template-button { + display: flex !important; + justify-content: center; + font-weight: 600; + font-size: 1rem; + } + + .download-template-button { + display: flex !important; + justify-content: center; + + .icon { + display: flex; + align-items: center; + margin: 0; + padding: 0; + } + + p { + font-weight: 500; + font-size: 1rem; + } + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss new file mode 100644 index 00000000000..ff5ace2af3e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss @@ -0,0 +1,13 @@ +/*@import 'normalize.css';*/ + +/*@import url("https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@400;500;700&family=Roboto:wght@400;500;700&display=swap");*/ + +@import "tailwindcss/base"; + +@import "tailwindcss/components"; + +@import "tailwindcss/utilities"; + +@import "./components/microplanning.scss"; +@import "./pages/employee/index.scss"; +@import "./pages/employee/campaign.scss"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss new file mode 100644 index 00000000000..5c6b56289d3 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss @@ -0,0 +1,109 @@ +@import url("../../index.scss"); +@import "../../typography.scss"; + +.summary-header { + @extend .typography.text-heading-l; + font-size: 2.25rem; +} +.date-field-container { + display: grid; + grid-template-columns: 20rem 20rem; + grid-gap: 1.5rem; + width: 70%; + padding-top: 0.3rem; + margin-top: 0rem; +} +.date-field { + display: grid; + grid-template-columns: 1fr 2fr; + align-items: start; +} +.campaign-type { + margin-right: 5rem; + padding-bottom: 1.2rem; + font-weight: bold; +} +.name-container { + margin-right: 4rem; + font-weight: bold; + text-wrap: nowrap; +} +.beneficiary-type { + margin-right: 5.4rem; + font-weight: bold; +} +.campaign-dates { + display: flex; + font-weight: bold; +} +.mandatory-date { + margin-top: 0.8rem; + margin-left: 0.5rem; + color: red !important; + font-size: 1rem; + font-weight: 700; +} +.description-type { + margin-top: 2rem; + margin-bottom: 2rem; +} +.name-description { + margin-top: 2rem; + margin-bottom: 2rem; +} +.dates-description { + margin-top: 1rem; + margin-bottom: 1rem; + padding-bottom: 1.2rem; +} +.selecting-boundary-div { + padding-top: 0.5rem; + .label-field-pair { + margin-bottom: 1.5rem; + } +} +.campaign-table { + border-collapse: collapse; + border-color: transparent; + border-width: 0rem 1.5rem; + tbody { + tr:hover { + background: rgba(#f47738, 0.12); + } + } +} +.info-points { + display: flex; + gap: 0.5rem; + margin-bottom: 0.5rem; +} +.infoClass{ + margin-bottom: 1.5rem +} +.headerWrapperClassName{ + display: none +} +.popup-close-svg{ + display: none; +} +.whoLogo{ + margin-top: -1rem; + margin-bottom: -1rem; +} + +.digit-popup-wrapper{ + &.popUpClass{ + width:45rem; + + .popUpFooter{ + .digit-popup-footer-buttons{ + margin-left: 0px; + width: 100%; + + button{ + flex:1; + } + } + } + } +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss new file mode 100644 index 00000000000..74296abb568 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss @@ -0,0 +1,331 @@ +@import "../../typography.scss"; + +.campaign-cycle-container { + .campaign-tabs-container { + } + .sub-tab-container { + margin-top: 5px; + padding: 1.5rem; + .card-text { + margin-bottom: 0; + } + } + .add-resource-container { + background-color: #fafafa; + border: 1px solid #d6d5d4; + border-radius: 0.4rem; + padding: 1rem; + margin-right: 1.5rem; + margin-bottom: 1.5rem; + .card-text { + margin: 0; + font-weight: 700; + } + .header-container { + display: flex; + align-items: flex-end; + justify-content: space-between; + } + } + .delete-resource-icon { + cursor: pointer; + font-weight: 600; + font-size: 1rem; + color: theme(digitv2.lightTheme.primary); + display: flex; + gap: 0.5rem; + align-items: center; + } + .add-resource-label-field-container { + display: grid; + grid-template-columns: 2fr 1fr; + grid-gap: 2rem; + .options-card { + max-height: 10rem !important; + } + } + .popup-wrap { + .popup-module-main { + max-height: 707px; + overflow-y: auto; + width: 99%; + &::-webkit-scrollbar { + width: 0.5rem; + background: transparent; + } + &::-webkit-scrollbar-thumb { + background: #d6d5d4; /* Color of the scrollbar thumb */ + border-radius: 5px; /* Adjust the border-radius for rounded corners */ + height: 0.5rem; + } + } + .popup-module-action-bar { + .selector-button-primary { + padding: 0.6rem 2.5rem; + height: unset; + margin: 1.5rem; + background-color: theme(digitv2.lightTheme.primary); + } + } + } +} +.selector-button-primary { + background-color: theme(digitv2.lightTheme.primary); +} +.campaign-breadcrumb { + margin: 0; + margin-bottom: 1.5rem; + color: theme(digitv2.lightTheme.primary) !important; +} +.sc-jlZhew.dVtbRz { + overflow: hidden; +} +.campaign-popup-module { + margin: auto; + width: calc(100% - 5rem); +} +.campaign-bulk-upload { + display: flex; + justify-content: space-between; + margin-bottom: 1.5rem; + .campaign-download-template-btn { + font-weight: 700; + } +} +.bulk-info-text { + margin-bottom: 1.5rem; +} +.delete-and-download-button { + display: flex; + gap: 1.5rem; +} +.bulk-upload-file { + .uploaded-file-container { + margin: 0; + margin-bottom: 1.5rem; + } +} +.uploaded-file-container { + margin-left: 0rem; +} +.upload-drag-drop-container { + background-color: #fafafa; + border: 1.5px dashed #d6d5d4; + border-radius: 5px; + padding: 1rem 1rem 1rem 1rem; + display: flex; + align-items: center; + flex-direction: column; + + .drag-drop-text { + text-decoration: none; + + .browse-text { + text-decoration: none; + color: theme(digitv2.lightTheme.primary); + transition: color 0.3s; + } + + .browse-text:hover { + color: theme(digitv2.lightTheme.primary); + text-decoration: underline; + cursor: pointer; + } + } +} + +.upload-drag-drop-container { + margin-left: 0rem; + .drag-drop { + color: #b1b4b6; + } + .browse-text { + text-decoration: underline; + color: theme(digitv2.lightTheme.primary); + transition: color 0.3s; + } +} + +.campaign-counter-container { + padding: 1.5rem; + padding-bottom: 0.5rem; + .card-text { + margin-top: 0; + } + .label-field-pair { + margin-bottom: 1rem; + .card-label { + font-weight: 700; + } + } + .date-field-container { + display: grid; + grid-template-columns: 18.75rem 18.75rem; + grid-gap: 1.5rem; + width: 100%; + } + .PlusMinus { + width: 30%; + input { + width: 100%; + } + } +} + +.campaign-tab-head { + padding: 1rem; + width: 12.5rem; + height: 3rem; + border-radius: 10px 10px 0px 0px; + background-color: #ffffff; + outline: none; + box-sizing: border-box; + font-weight: 700; + font-size: 1rem; + font-family: "Roboto"; + color: #505a5f; + margin-bottom: -6px; + border: 1px solid #d6d5d4; + background-color: #fafafa; + &.active { + height: 3.375rem; + background-color: #ffffff; + outline: none; + font-weight: bold; + color: theme(digitv2.lightTheme.primary); + border: 1px solid theme(digitv2.lightTheme.primary); + border-bottom: 4px solid theme(digitv2.lightTheme.primary); + box-sizing: border-box; + font-size: 1.5rem; + } + :focus { + outline: none; + } +} +.campaign-sub-tab-head { + outline: none; + background-color: #ffffff; + color: theme(digitv2.lightTheme.primary); + border: 1px solid theme(digitv2.lightTheme.primary); + height: 2rem; + width: 9.188rem; + font-size: 1rem; + font-weight: 400; + &.active { + background-color: theme(digitv2.lightTheme.primary); + color: #ffffff; + font-weight: bold; + outline: none; + height: 2rem; + width: 9.188rem; + font-family: "Roboto"; + font-weight: 700; + font-size: 1rem; + } +} +.tab-content-header { + margin-top: 1.5rem; + margin-bottom: 1.5rem !important; +} + +.delivery-rule-container { + padding-top: 0; + .card-header { + .title { + margin: 0 !important; + } + font-size: 1.5rem !important; + margin: 0; + display: flex; + align-content: center; + justify-content: space-between; + } + .attribute-container { + border: 1px solid #d6d5d4; + background-color: #fafafa; + padding: 1rem; + padding-top: 0; + .add-attribute { + width: 74.5%; + justify-content: center; + h2 { + font-size: 1rem; + font-family: Roboto; + width: unset !important; + font-weight: 600; + } + } + } +} +.attribute-field-wrapper { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + align-items: center; + gap: 2.5rem; + .label-field-pair { + flex-direction: column; + align-items: flex-start !important; + .card-label.card-label-smaller { + font-weight: 700; + } + .employee-select-wrap.form-field { + width: 100%; + } + .digit-employee-card-input { + margin-bottom: 0; + } + } + .options-card { + max-height: 10rem !important; + } + .card-label { + margin-bottom: 0.5rem; + } +} +.add-rule-btn { + margin: auto; + h2 { + font-family: Roboto; + font-size: 1rem; + font-weight: 600; + } +} +.add-product-btn { + h2 { + font-family: Roboto; + font-size: 1rem; + font-weight: 600; + } +} +.popup-wrap.campaign-product-wrapper { + .popup-module { + width: 70%; + padding-left: 1.5rem; + padding-bottom: 1.5rem; + .header-wrap { + font-size: 1.5rem; + font-weight: 700; + .header-content.popup-header-fix { + margin-top: 1.5rem; + } + } + } + .popup-module-action-bar { + margin-top: 1.5rem; + margin-right: 1.5rem; + } +} +.search-button-wrapper { + grid-column-end: -1 !important; + flex-direction: row !important; +} +.add-resource-modal { +} +.add-resource-wrapper { + .link { + color: theme(digitv2.lightTheme.primary); + } +} +.digit-toast-success { + margin-bottom: -0.5rem; +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss new file mode 100644 index 00000000000..295d90c1264 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss @@ -0,0 +1,173 @@ +@import "../../typography.scss"; + +/* language selection issue*/ +.customBtn-selected { + background-color: theme(digitv2.lightTheme.primary); +} + +/* login screen issue*/ + +.primary-label-btn { + color: theme(digitv2.lightTheme.primary); +} + +/* landing screen issue*/ + +.employeeCard { + .complaint-links-container .header .logo { + background-color: theme(digitv2.lightTheme.primary); + } + + .complaint-links-container .body { + &.link { + color: theme(digitv2.lightTheme.primary); + } + .inbox-total { + background-color: theme(digitv2.lightTheme.primary); + } + } +} + +.employee .topbar .right .user-img-txt { + background-color: theme(digitv2.lightTheme.primary); +} +/* button component issue*/ + +.action-bar-wrap { + .submit-bar { + background-color: theme(digitv2.lightTheme.primary); + } +} + +.jk-digit-secondary-btn { + color: theme(digitv2.lightTheme.primary); + border-color: theme(digitv2.lightTheme.primary); + + svg { + fill: theme(digitv2.lightTheme.primary); + + path { + fill: theme(digitv2.lightTheme.primary); + } + } +} +.error-boundary .error-container button { + background-color: theme(digitv2.lightTheme.primary); +} + +/* inbox screen issue*/ + +.inbox-search-wrapper { + .search-tabs-container .search-tab-head-selected { + color: theme(digitv2.lightTheme.primary); + border-color: theme(digitv2.lightTheme.primary); + } + .submit-bar { + background-color: theme(digitv2.lightTheme.primary); + } + .search-component-table .link { + color: theme(digitv2.lightTheme.primary); + } + .link-label { + color: theme(digitv2.lightTheme.primary) !important; + } +} +.drag-drop-container .drag-drop-text .browse-text { + color: theme(digitv2.lightTheme.primary); +} +/* toast new componnet css added */ + +.toast-success { + gap: 0.5rem; + height: 3rem; + padding: 0.75rem 0.5rem 0.75rem 0.75rem !important; + background-color: theme(digitv2.alert.success); + transition: bottom 0.5s ease; + grid-gap: 0.5rem; + &.error { + background-color: theme(digitv2.alert.error) !important; + } + + &.warning { + background-color: #f19100; + + &.warning-buttons { + @apply block; + } + } + + h2 { + @apply text-left overflow-hidden whitespace-no-wrap flex-grow flex items-center h-6; + letter-spacing: 0rem; + color: theme(digitv2.lightTheme.paper); + margin: 0rem; + text-overflow: ellipsis; + font-family: Roboto; + font-weight: 500; + font-size: 1.25rem; + font-style: normal; + } + svg { + @apply flex-shrink-0; + } +} + +@keyframes slideInFromBottom { + from { + bottom: -3rem; + } + to { + bottom: 4rem; + } +} + +.toast-success.animate { + animation: slideInFromBottom 0.5s ease forwards; +} + +@media screen and (max-width: 768px) { + .topbar { + background: #0b4b66 !important; + color: #fff; + } +} +header { + @extend .typography.text-heading-xl; +} +.digit-button-primary{ + background-color: theme(digitv2.lightTheme.primary) !important; +} +.digit-button-secondary{ + .icon-label-container{ + h2{ + color: theme(digitv2.lightTheme.primary) !important; + } + } +} + +/*.digit-popup-wrap { + background: rgba(0, 0, 0, 0.7); + @apply flex fixed w-full h-full overflow-auto top-0 left-0 min-h-screen; + z-index: 10000; + max-width: 100% !important; + max-height: 100% !important; +} + +@screen dt { + .digit-popup-wrap { + background: rgba(0, 0, 0, 0.7); + @apply min-h-screen; + } +} + +.digit-popup-close-icon { + @apply flex justify-end; +}*/ + +.employee{ + .digit-employeeSidebar{ + .sidebar{ + z-index:999 + } + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss new file mode 100644 index 00000000000..2b989e87305 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss @@ -0,0 +1,481 @@ +@import "./campaignCycle.scss"; +@import "./coreOverride.scss"; +@import "../../typography.scss"; + +.wbh-header-container { + margin-top: 1.5rem; +} +.main.digit-home-main { + margin-left: 92px; + .employee-app-wrapper.digit-home-app-wrapper { + margin-left: 0; + margin-right: 2rem; + .ground-container.digit-home-ground { + padding: 0; + .employee-app-container.digit-home-employee-app { + .ground-container.moduleCardWrapper.gridModuleWrapper.digit-home-moduleCardWrapper { + gap: 2.5rem; + margin-top: 2rem; + padding: 0; + display: grid !important; + grid-template-columns: repeat(auto-fill, minmax(263px, 1fr)); + .employeeCard.customEmployeeCard.card-home.home-action-cards { + margin: 0 !important; + min-width: 263px !important; + width: auto !important; + } + } + } + } + } +} +.campaign-cycle-container { + .popup-header-fix { + margin-top: 1.5rem !important; + } +} + +.tag.inbox-tag { + max-width: fit-content; + background-color: #d6d5d4; + border-radius: 2rem; + padding: 0.5rem; + display: flex; + align-items: center; + height: 2rem; + margin-bottom: 0.7rem; + grid-gap: 0.2rem; + gap: 0.2rem; +} +.mandatory-span { + margin-left: 0.5rem; + color: red !important; + font-size: 1rem; + font-weight: 700; +} + +.digit-employee-card-input.numeric { + margin-bottom: unset; +} + +.actionBarClass { + display: flex; + justify-content: space-between; + flex-direction: row-reverse; + z-index: 0; +} +.previous-button { + margin-left: 4rem; + min-width: 12.5rem; +} +.info-text { + padding-bottom: 1.5rem; +} + +.view-composer-header-section { + display: flex; + justify-content: space-between; + align-items: baseline; +} +.card-with-background { + margin-top: 1rem; + .card-head { + margin-bottom: 1rem; + color: #505a5f; + } +} +.no-data-found { + display: flex; + flex-direction: column; + align-items: center; + .error-msg { + margin-top: 1rem; + } +} +.search-tab-head { + color: #505a5f; +} +.search-tabs-container { + border-bottom: none; + margin-bottom: 0; +} +.delivery-preview-card { + margin-bottom: 1.5rem !important; + background-color: #fafafa; + border: 1px solid #d6d5d4; + width: 70%; + .custom-table-label { + font-size: 1.5rem; + font-weight: 700; + color: #505a5f; + margin-bottom: 1rem; + } + .campaign-attribute-table { + margin-bottom: 1rem; + border: 1px solid #d6d5d4; + overflow: hidden; + border-radius: 4px; + table { + border-width: 0px !important; + background-color: #fafafa; + border: 1px solid #d6d5d4; + border-collapse: collapse; + border-radius: 1rem; + tbody { + tr:nth-child(odd) { + background-color: white; + } + } + th { + border-right: 1px solid #d6d5d4; + } + th:last-child { + border-right: none; + } + td { + padding: 1rem; + border-right: 1px solid #d6d5d4; + } + td:last-child { + padding: 1rem; + border-right: none; + } + } + } + .campaign-product-table { + margin-bottom: 1rem; + border: 1px solid #d6d5d4; + overflow: hidden; + border-radius: 4px; + table { + background-color: #fafafa; + border: 1px solid #d6d5d4; + border-collapse: collapse; + border-radius: 1rem; + border-width: 0px !important; + tbody { + background-color: #fff; + tr:nth-child(odd) { + background-color: white; + } + } + th { + border-right: 1px solid #d6d5d4; + } + th:last-child { + border-right: none; + } + td { + padding: 1rem; + border-right: 1px solid #d6d5d4; + } + td:last-child { + border-right: none; + } + } + } +} +.cycle-paragraph { + font-weight: 700; + font-size: 24px; + color: #505a5f; + margin-top: 0.5rem; +} +.header-end { + margin-right: 1rem; +} +.digit-stepper-container { + margin-bottom: 1.5rem; +} +.employee-app-wrapper { + margin: 0rem 1rem; +} +input[type="date"]::-webkit-calendar-picker-indicator { + position: absolute; + right: 5px; + top: 20%; + transform: translateY(-10%); +} +.campaign-preview-edit-container { + display: flex; + gap: 1rem; + span { + color: theme(digitv2.lightTheme.primary); + } +} +.campaign-attribute-table { + border: 1px solid #d6d5d4; + overflow: hidden; + border-radius: 4px; + tbody { + tr:nth-child(odd) { + background-color: white; + } + } +} +tbody { + tr:nth-child(odd) { + background-color: white; + } +} +.popup-wrap.campaign-data-preview { + flex-direction: column; +} + +.digit-employee-card-input.numeric { + pointer-events: none; +} +.product-tag-container { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; + margin-bottom: 1rem; +} + +.workbench-download-template-btn { + font-weight: 700; +} +.digit-employee-card-input.numeric { + text-align: center; +} +.in-between { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 2rem; + @media screen and (min-width: 1024px) { + grid-gap: 10rem; + } +} +.setup-campaign { + .setup-campaign-card { + padding-bottom: 1.5rem; + } + .digit-dropdown-options-card { + max-height: 10rem !important; + } + .digit-field { + margin-bottom: 0 !important; + } +} +.campaign-summary-container { + .setup-campaign-card { + .employeeCard.employeeCard-override { + padding: 1.5rem; + margin-bottom: 1.5rem !important; + } + } + .row { + justify-content: flex-start; + gap: 5rem; + h2 { + margin: 0; + width: 272px; + } + .value { + width: unset; + p { + margin: 0; + } + } + } + .digit-infobanner-wrap.error { + margin-left: 0; + margin-bottom: 1.5rem; + min-width: 100%; + .digit-button-primary { + height: 1.5rem; + background-color: #d4351c !important; + .icon-label-container.primary.large { + font-size: 14px; + .digit-button-label { + font-size: 14px; + color: #ffffff; + } + } + } + } +} +.view-composer-header-section { + .employee-card-sub-header { + @extend .typography.text-heading-m; + margin-bottom: 1.5rem; + } + .employee-card-sub-header.error { + color: #d4351c; + display: flex; + align-items: center; + gap: 0.5rem; + } +} +.add-new-product-container { + border: 1px solid #d6d5d4; + background-color: #fafafa; + width: 70%; + padding-top: 0; + .heading-bar { + font-weight: 700; + display: flex; + align-items: baseline; + justify-content: space-between; + .card-text { + margin-top: 1rem; + margin-bottom: 1rem; + } + } + .label-field-pair { + gap: 5rem; + align-items: baseline; + .product-label-field { + width: 12rem; + text-wrap: nowrap; + font-weight: 700; + } + } +} +.page-padding-fix { + margin-top: 1.5rem; +} +.addProductActionClass { + display: flex; + flex-direction: row-reverse; + justify-content: space-between; + .submit-bar { + width: max-content; + padding-left: 1.5rem; + padding-right: 1.5rem; + } +} +.loginFormStyleEmployee { + .loginCardClassName { + .digit-header-content { + &:not(label) { + display: flex; + justify-content: center; + } + } + } +} +.selecting-boundaries-dropdown { + .digit-multiselectdropdown-server { + max-height: 15rem; + } +} +.hover { + cursor: pointer; +} +.digit-dropdown-employee-select-wrap { + .digit-dropdown-employee-select-wrap--elipses { + font-size: 1rem !important; + } +} +.digit-dropdown-employee-select-wrap.language-dropdown { + .digit-dropdown-options-card { + min-width: fit-content; + } +} +.digit-popup-wrapper.boundaries-pop-module.default { + width: 36rem; + .digit-popup-footer { + .digit-popup-footer-buttons { + width: 100% !important; + display: grid; + grid-template-columns: 1fr 1fr; + .digit-button-secondary { + width: 100%; + } + .digit-button-primary { + width: 100%; + } + } + } +} +.campaign-type-alert-button { + .digit-button-label { + width: 100% !important; + } +} +.campaign-pop-module { + padding: 1.5rem; + border-radius: 4px; + width: 36rem; +} +.campaign-modal-heading { + font-size: 2rem; + font-weight: 700; + margin: 0 !important; +} +.campaign-pop-main { + font-size: 1.25rem; + padding: 0 !important; + font-size: 400; + .card-text { + margin-bottom: 1.5rem !important; + } + .popup-module-action-bar.campaign-pop-action { + .selector-button-border { + background-color: #ffffff; + border: 1px solid #c84c0e; + h2 { + color: #c84c0e !important; + } + } + } +} + +.digit-toast-success { + max-width: 90%; + margin-left: auto; + margin-right: auto; + height: auto; + .toast-label { + line-height: 1.5; + word-break: break-word; + height: auto; + white-space: unset; + } +} + +.digit-dropdown-select.error { + border: 1px solid #d4351c; +} +.campaign-type-wrapper { + .digit-error-icon-message-wrap { + margin-top: 4px; + font-size: 14px; + } +} +.individualElement { + h2 { + color: theme(digitv2.lightTheme.text-primary); + } +} +.link { + color: #c84c0e !important; +} +.employeeCard.employeeCard-override.card-error { + border: 1px solid #d4351c; +} +.label-field-pair.delivery-type-radio { + gap: 5rem; + .digit-radio-options-wrap { + gap: 2rem; + margin-bottom: 0 !important; + .radio-option-container { + margin-bottom: 0; + align-items: center; + } + } +} +.bold { + font-weight: 700; +} +.summary-doc-error { + p { + margin-top: 0; + margin-bottom: 0; + } + .digit-infobanner-wrap.error { + margin-bottom: 0.5rem; + margin-top: 1.5rem; + } +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss new file mode 100644 index 00000000000..4a50014cf88 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss @@ -0,0 +1,512 @@ +.typography { + &.text-heading-xl { + font-family: theme(digitv2.fontFamily.rc); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.heading-xl.desktop); + } + + @media (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.heading-xl.tablet); + } + + @media (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.heading-xl.mobile); + } + } + + &.text-heading-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.heading-l.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.heading-l.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.heading-l.mobile); + } + } + + &.text-heading-m { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.heading-m.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.heading-m.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.heading-m.desktop); + } + } + + &.text-heading-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.heading-s.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.heading-s.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.heading-s.mobile); + } + } + + &.text-heading-xs { + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.heading-xs.mobile); + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + } + } + + &.text-caption-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.caption-l.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.caption-l.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.caption-l.mobile); + } + } + + &.text-caption-m { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.caption-m.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.caption-m.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.caption-m.mobile); + } + } + + &.text-caption-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.caption-s.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.caption-s.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.caption-s.desktop); + } + } + + &.text-body-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.regular); + color: theme(digitv2.lightTheme.text-primary); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.body-l.desktop); + line-height: theme(digitv2.lineHeight.line-height-body-l.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.body-l.tablet); + line-height: theme(digitv2.lineHeight.line-height-body-l.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.body-l.mobile); + line-height: theme(digitv2.lineHeight.line-height-body-l.mobile); + } + } + + &.text-body-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.regular); + color: theme(digitv2.lightTheme.text-primary); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.body-s.desktop); + line-height: theme(digitv2.lineHeight.line-height-body-s.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.body-s.tablet); + line-height: theme(digitv2.lineHeight.line-height-body-s.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.body-s.mobile); + line-height: theme(digitv2.lineHeight.line-height-body-s.mobile); + } + } + + &.text-body-xs { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.regular); + color: theme(digitv2.lightTheme.text-primary); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.body-xs.desktop); + line-height: theme(digitv2.lineHeight.line-height-body-xs.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.body-xs.tablet); + line-height: theme(digitv2.lineHeight.line-height-body-xs.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.body-xs.mobile); + line-height: theme(digitv2.lineHeight.line-height-body-xs.mobile); + } + } + + &.text-label { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.regular); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.label.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.label.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.label.mobile); + } + } + + &.text-link { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + text-decoration: theme(digitv2.textDecorationLine.underline); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.link.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.link.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.link.mobile); + } + } + + &.heading-xl { + font-family: theme(digitv2.fontFamily.rc); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.heading-xl.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.heading-xl.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.heading-xl.desktop); + } + } + + &.heading-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.heading-l.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.heading-l.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.heading-l.desktop); + } + } + + &.heading-m { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.heading-m.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.heading-m.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.heading-m.desktop); + } + } + + &.heading-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.heading-s.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.heading-s.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.heading-s.desktop); + } + } + + &.heading-xs { + font-size: theme(digitv2.fontSize.heading-xs.mobile); + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + } + + &.caption-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.caption-l.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.caption-l.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.caption-l.desktop); + } + } + + &.caption-m { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.caption-m.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.caption-m.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.caption-m.desktop); + } + } + + &.caption-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.caption-s.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.caption-s.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.caption-s.desktop); + } + } + + &.body-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.body-l.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.body-l.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.body-l.desktop); + } + } + + &.body-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.body-s.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.body-s.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.body-s.desktop); + } + } + + &.body-xs { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.body-xs.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.body-xs.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.body-xs.desktop); + } + } + + &.label { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.label.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.label.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.label.desktop); + } + } + + &.link { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + text-decoration: theme(digitv2.textDecorationLine.underline); + font-size: theme(digitv2.fontSize.link.desktop); + } + + &.button { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.medium); + font-size: theme(digitv2.fontSize.button.desktop); + } +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js new file mode 100644 index 00000000000..c9b2a06dedf --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js @@ -0,0 +1,233 @@ +module.exports = { + future: { + removeDeprecatedGapUtilities: true, + purgeLayersByDefault: true, + }, + purge: { enabled: true, content: ["./example/index.html"] }, + theme: { + screens: { + dt: "780px", + sm: { max: "425px" }, + }, + colors: { + primary: { + light: "#F18F5E", + main: "#F47738", + dark: "#C8602B", + }, + secondary: "#22394D", + text: { + primary: "#0B0C0C", + secondary: "#505A5F", + }, + link: { + normal: "#1D70B8", + hover: "#003078", + }, + border: "#D6D5D4", + inputBorder: "#464646", + "input-border": "#464646", + focus: "#F47738", + error: "#D4351C", + success: "#00703C", + black: "#000000", + grey: { + dark: "#9E9E9E", + mid: "#EEEEEE", + light: "#FAFAFA", + bg: "#E3E3E3", + }, + white: "#FFFFFF", + }, + fontFamily: { + sans: ["Roboto", "sans-serif"], + rc: ['"Roboto Condensed"', "sans-serif"], + }, + fontSize: { + "heading-xl-dt": ["48px", "56px"], + "heading-xl": ["32px", "40px"], + "heading-l-dt": ["36px", "40px"], + "heading-l": ["24px", "32px"], + "heading-m-dt": ["24px", "32px"], + "heading-m": ["18px", "28px"], + "heading-s": ["16px", "24px"], + "caption-xl-dt": ["27px", "32px"], + "caption-xl": ["18px", "26px"], + "caption-l-dt": ["24px", "28px"], + "caption-l": ["18px", "21px"], + "caption-m-dt": ["19px", "23px"], + "caption-m": ["16px", "19px"], + "form-field": ["16px", "20px"], + "body-l-dt": ["19px", "28px"], + "body-l": ["16px", "24px"], + "body-s-dt": ["16px", "24px"], + "body-s": ["14px", "16px"], + legend: ["19px", "23px"], + link: ["16px", "24px"], + "text-btn": ["16px", "24px"], + }, + fontWeight: { + regular: 400, + medium: 500, + bold: 700, + }, + padding: { + sm: "8px", + md: "16px", + lg: "24px", + xl: "36px", + }, + margin: { + xs: "4px", + sm: "8px", + md: "16px", + lg: "24px", + xl: "64px", + }, + borderWidth: { + default: "1px", + 0: "0", + 2: "1px", + 4: "4px", + 10: "10px", + }, + boxShadow: { + card: "0 1px 2px 0 rgba(0, 0, 0, 0.16)", + radiobtn: "0 0 0 5px #F47738", + }, + inset: { + 0: 0, + 6: "6px", + 10: "10px", + }, + extend: {}, + digitv2: { + lightTheme: { + primary: "#C84C0E", + "text-color-primary": "#0B0C0C", + "text-color-secondary": "#505A5F", + "text-color-disabled": "#B1B4B6", + background: "#EEEEEE", + paper: "#FFFFFF", + "paper-secondary": "#FAFAFA", + divider: "#D6D5D4", + "header-sidenav": "#0B4B66", + "input-border": "#505A5F", + "primary-bg": "#FEEFE7", + "text-primary": "#363636", + "error-v2": "#D4351C", + }, + alert: { + error: "#b91900", + "error-bg": "#EFC7C1", + success: "#00703C", + "success-bg": "#BAD6C9", + info: "#3498DB", + "info-bg": "#C7E0F1", + }, + chart: { + "chart-1": "#048BD0", + "chart-1-gradient": "#048BD0", + "chart-2": "#FBC02D", + "chart-2-gradient": "#FBC02D", + "chart-3": "#8E29BF", + "chart-4": "#EA8A3B", + "chart-5": "#0BABDE", + }, + fontSize: { + "heading-xl": { + mobile: "2rem", + tablet: "2.25rem", + desktop: "2.5rem", + }, + "heading-l": { + mobile: "1.5rem", + tablet: "1.75rem", + desktop: "2rem", + }, + "heading-m": { + mobile: "1.25rem", + tablet: "1.375rem", + desktop: "1.5rem", + }, + "heading-s": { + mobile: "1rem", + tablet: "1rem", + desktop: "1rem", + }, + "heading-xs": { + mobile: "0.75rem", + }, + "caption-l": { + mobile: "1.5rem", + tablet: "1.75rem", + desktop: "1.75rem", + }, + "caption-m": { + mobile: "1.25rem", + tablet: "1.5rem", + desktop: "1.5rem", + }, + "caption-s": { + mobile: "1rem", + tablet: "1.25rem", + desktop: "1.25rem", + }, + "body-l": { + mobile: "1rem", + tablet: "1.25rem", + desktop: "1.25rem", + }, + "body-s": { + mobile: "0.875rem", + tablet: "1rem", + desktop: "1rem", + }, + "body-xs": { + mobile: "0.75rem", + tablet: "0.875rem", + desktop: "0.875rem", + }, + label: { + mobile: "1rem", + tablet: "1rem", + desktop: "1rem", + }, + link: { + mobile: "1rem", + tablet: "1rem", + desktop: "1rem", + }, + }, + fontFamily: { + sans: ["Roboto"], + rc: ['"Roboto Condensed"'], + }, + fontStyle: { + normal: "normal", + italic: "italic", + }, + textDecorationLine: { + underline: "underline", + }, + fontWeight: { + regular: 400, + medium: 500, + bold: 700, + }, + lineHeight: { + "line-height-body-l": { mobile: "1.5rem", tablet: "1.75rem", desktop: "1.75rem" }, + "line-height-body-s": { mobile: "1.0938rem", tablet: "1.5rem", desktop: "1.5rem" }, + "line-height-body-xs": { mobile: "1.125rem", tablet: "1.5rem", desktop: "1.5rem" }, + normal: "normal", + }, + screens: { + mobile: "400px", + tablet: "768px", + desktop: "1024px", + }, + }, + }, + variants: {}, + plugins: [], +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md new file mode 100644 index 00000000000..0d206b3021e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md @@ -0,0 +1,159 @@ +# digit-ui-module-workbench + +## Install + +```bash +npm install --save digit-ui-module-workbench +``` + +## Limitation + +```bash +This Package is more specific to DIGIT-UI's can be used across mission's +``` + +## Usage + +After adding the dependency make sure you have this dependency in + +```bash +frontend/micro-ui/web/package.json +``` + +```json +"@egovernments/digit-ui-module-workbench":"1.0.0", +``` + +then navigate to App.js + +```bash + frontend/micro-ui/web/src/App.js +``` + +```jsx +/** add this import **/ + +import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; + +/** inside enabledModules add this new module key **/ + +const enabledModules = ["workbench"]; + +/** inside init Function call this function **/ + +const initDigitUI = () => { + initWorkbenchComponents(); +}; + +``` + +In MDMS + +_Add this configuration to enable this module [MDMS Enabling Workbench Module](https://github.com/egovernments/works-mdms-data/blob/588d241ba3a9ab30f4d4c2c387a513da811620ca/data/pg/tenant/citymodule.json#L227)_ + +## List of Screens available in this versions were as follows + +1 . Search Master Data + > -Provides a screen based on Schema and renders the search result if data is present + > -It also provides a dynamic filter based on which data can be filtered + + +2 . Add Master Data based on selected schema + > -Provides a screen to add new master data according to the schema + > -Provides a Dropdown if it has any referenced master + +3 . Update Master data for selected data. + > -View the master data from search screen + > -Disable/Enable the master data if required + > -Update the master data value except the unique-identifier field mentioned in the schema + + + +4 . Localisation screens + > -Provides a screen to search the localisation present in the environment + > -Add new localisation + > -Update existing localisation + > -Bulk Upload of Localisation data + +5 . MDMS UI Schema + +6 . Data push for any API based on schema + +### Mandatory changes to use Workbench module + +1 . Assuming core module is already updated with 1.5.38+ and related changes were taken + +2 . add the following hook method in micro-ui-internals/packages/libraries/src/hooks/useCustomAPIMutationHook.js + +reference:: +https://github.com/egovernments/DIGIT-Dev/blob/6e711bdc005c226c7debd533209681fc77078a3e/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomAPIMutationHook.js + +3 . add the following utility method in micro-ui-internals/packages/libraries/src/utils/index.js +```jsx +didEmployeeHasAtleastOneRole + +const didEmployeeHasAtleastOneRole = (roles = []) => { + return roles.some((role) => didEmployeeHasRole(role)); +}; + +``` + +4 . stylesheet link has to be added +```jsx + +``` +Reference commit for the enabling workbench +https://github.com/egovernments/DIGIT-OSS/pull/99/commits/6e711bdc005c226c7debd533209681fc77078a3e + + + +### Changelog + +```bash +1.0.1-beta.1 Republished after merging with Master due to version issues. +1.0.0-beta.14 Added info message in localisation search +1.0.0-beta.13 Added new role to support hcm localisation create +1.0.0-beta.13 Added customisable label for custom dropdown through workbench ui schema +1.0.0-beta.11 Added customisable label for custom dropdown through workbench ui schema +1.0.0-beta.10 fixed the dropdown undefined issue +1.0.0-beta.9 Added new role to support hcm manage masters +1.0.0-beta.8 minor fixes +1.0.0-beta.7 Added Bulk Upload Ui for MDMS Add +1.0.0-beta.6 Added Bulk Upload Ui for MDMS Add +1.0.0-beta.5 Fixed some loading issue +1.0.0-beta.2 custom api support added +1.0.0-beta.1 republished due to some version issues +1.0.1 Fixes related to the limits +1.0.0 Workbench v1.0 release +1.0.0-beta workbench base version beta release +0.0.3 readme updated +0.0.2 readme updated +0.0.1 base version +``` + +### Contributors + +- [jagankumar-egov](https://github.com/jagankumar-egov) +- [nipun-egov](https://github.com/nipun-egov) + + +## License + +[MIT](https://choosealicense.com/licenses/mit/) + +## Documentation + +Documentation Site (https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) +Workbench Documentation(https://workbench.digit.org/platform/functional-specifications/workbench-ui) + +## Maintainer + +- [jagankumar-egov](https://www.github.com/jagankumar-egov) + + +### Published from DIGIT Frontend +DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/master) + + +![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) + diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json new file mode 100644 index 00000000000..41e43fdb6fd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json @@ -0,0 +1,51 @@ +{ + "name": "@egovernments/digit-ui-module-campaign-manager", + "version": "0.0.1", + "description": "Campaign", + "main": "dist/index.js", + "module": "dist/index.modern.js", + "source": "src/Module.js", + "files": [ + "dist" + ], + "scripts": { + "start": "microbundle-crl watch --no-compress --format modern,cjs", + "build": "microbundle-crl --compress --no-sourcemap --format cjs", + "prepublish": "yarn build" + }, + "peerDependencies": { + "react": "17.0.2", + "react-router-dom": "5.3.0" + }, + "dependencies": { + "@egovernments/digit-ui-react-components": "1.8.2-beta.6", + "@egovernments/digit-ui-components": "0.0.2-beta.1", + "@rjsf/core": "5.10.0", + "@rjsf/utils": "5.10.0", + "@rjsf/validator-ajv8": "5.10.0", + "ajv": "8.12.0", + "react": "17.0.2", + "react-date-range": "1.4.0", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "react-select": "5.7.4", + "react-table": "7.7.0", + "xlsx": "0.17.5", + "react-drag-drop-files": "^2.3.10", + "@cyntler/react-doc-viewer": "1.10.3" + }, + "author": "JaganKumar ", + "license": "MIT", + "keywords": [ + "digit", + "egov", + "dpg", + "digit-ui", + "workbench", + "campaign", + "Campaign" + ] +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js new file mode 100644 index 00000000000..cc2f33443d4 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js @@ -0,0 +1,141 @@ +import { Loader, TourProvider } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useRouteMatch } from "react-router-dom"; +import EmployeeApp from "./pages/employee"; +import { CustomisedHooks } from "./hooks"; +import { UICustomizations } from "./configs/UICustomizations"; +import CampaignCard from "./components/CampaignCard"; +import CycleConfiguration from "./pages/employee/CycleConfiguration"; +import DeliverySetup from "./pages/employee/deliveryRule"; +import TimelineCampaign from "./components/TimelineCampaign"; +import CampaignDates from "./components/CampaignDates"; +import CampaignType from "./components/CampaignType"; +import CampaignName from "./components/CampaignName"; +import MyCampaign from "./pages/employee/MyCampaign"; +import CampaignSummary from "./components/CampaignSummary"; +import CycleDetaisPreview from "./components/CycleDetaisPreview"; +import Response from "./pages/employee/Response"; +import SelectingBoundaries from "./components/SelectingBoundaries"; +import UploadData from "./components/UploadData"; +import CampaignSelection from "./components/CampaignType"; +import CampaignDocumentsPreview from "./components/CampaignDocumentsPreview"; +import AddProduct from "./pages/employee/AddProduct"; +import AddProductField from "./components/AddProductField"; +import CycleDataPreview from "./components/CycleDataPreview"; +import { ErrorBoundary } from "@egovernments/digit-ui-components"; +import CampaignResourceDocuments from "./components/CampaignResourceDocuments"; + +/** + * The CampaignModule function fetches store data based on state code, module code, and language, and + * renders the EmployeeApp component within a TourProvider component if the data is not loading. + * @returns The CampaignModule component returns either a Loader component if data is still loading, or + * a TourProvider component wrapping an EmployeeApp component with specific props passed to it. + */ +const CampaignModule = ({ stateCode, userType, tenants }) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + const { data: BOUNDARY_HIERARCHY_TYPE } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }], { + select: (data) => { + return data?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy; + }, + }); + + const moduleCode = ["campaignmanager", "workbench", "mdms", "schema", "hcm-admin-schemas", `boundary-${BOUNDARY_HIERARCHY_TYPE}`]; + const { path, url } = useRouteMatch(); + const language = Digit.StoreData.getCurrentLanguage(); + const { isLoading, data: store } = Digit.Services.useStore({ + stateCode, + moduleCode, + language, + }); + + if (isLoading) { + return ; + } + + return ( + + + + + + ); +}; + +const componentsToRegister = { + CampaignModule: CampaignModule, + CampaignCard: CampaignCard, + UploadData, + DeliveryRule: DeliverySetup, + CycleConfiguration: CycleConfiguration, + TimelineCampaign, + CampaignDates, + CampaignType, + CampaignName, + MyCampaign, + CampaignSummary, + CycleDetaisPreview, + Response, + SelectingBoundaries, + CampaignSelection, + CampaignDocumentsPreview: CampaignDocumentsPreview, + AddProduct, + AddProductField, + CycleDataPreview, + CampaignResourceDocuments, +}; + +const overrideHooks = () => { + Object.keys(CustomisedHooks).map((ele) => { + if (ele === "Hooks") { + Object.keys(CustomisedHooks[ele]).map((hook) => { + Object.keys(CustomisedHooks[ele][hook]).map((method) => { + setupHooks(hook, method, CustomisedHooks[ele][hook][method]); + }); + }); + } else if (ele === "Utils") { + Object.keys(CustomisedHooks[ele]).map((hook) => { + Object.keys(CustomisedHooks[ele][hook]).map((method) => { + setupHooks(hook, method, CustomisedHooks[ele][hook][method], false); + }); + }); + } else { + Object.keys(CustomisedHooks[ele]).map((method) => { + setupLibraries(ele, method, CustomisedHooks[ele][method]); + }); + } + }); +}; + +/* To Overide any existing hook we need to use similar method */ +const setupHooks = (HookName, HookFunction, method, isHook = true) => { + window.Digit = window.Digit || {}; + window.Digit[isHook ? "Hooks" : "Utils"] = window.Digit[isHook ? "Hooks" : "Utils"] || {}; + window.Digit[isHook ? "Hooks" : "Utils"][HookName] = window.Digit[isHook ? "Hooks" : "Utils"][HookName] || {}; + window.Digit[isHook ? "Hooks" : "Utils"][HookName][HookFunction] = method; +}; +/* To Overide any existing libraries we need to use similar method */ +const setupLibraries = (Library, service, method) => { + window.Digit = window.Digit || {}; + window.Digit[Library] = window.Digit[Library] || {}; + window.Digit[Library][service] = method; +}; + +/* To Overide any existing config/middlewares we need to use similar method */ +const updateCustomConfigs = () => { + setupLibraries("Customizations", "commonUiConfig", { ...window?.Digit?.Customizations?.commonUiConfig, ...UICustomizations }); + // setupLibraries("Utils", "parsingUtils", { ...window?.Digit?.Utils?.parsingUtils, ...parsingUtils }); +}; + +/** + * The `initCampaignComponents` function initializes campaign components by overriding hooks, updating + * custom configurations, and registering components. + */ +const initCampaignComponents = () => { + overrideHooks(); + updateCustomConfigs(); + Object.entries(componentsToRegister).forEach(([key, value]) => { + Digit.ComponentRegistryService.setComponent(key, value); + }); +}; + +export { initCampaignComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js new file mode 100644 index 00000000000..94a73fd6b24 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js @@ -0,0 +1,144 @@ +import React, { useState, useEffect } from "react"; +import { AddIcon, Button, Card, CardText, Header, TextInput, Dropdown } from "@egovernments/digit-ui-react-components"; +import { useTranslation } from "react-i18next"; +import { LabelFieldPair } from "@egovernments/digit-ui-react-components"; +import { DustbinIcon } from "./icons/DustbinIcon"; +// import { productType } from "../configs/productType"; +import { PRIMARY_COLOR } from "../utils"; + +const AddProductField = ({ onSelect }) => { + const { t } = useTranslation(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const { isLoading: productTypeLoading, data: productType } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "productType" }], { + select: (data) => { + return data?.["HCM-ADMIN-CONSOLE"]?.productType; + }, + }); + const [productFieldData, setProductFieldData] = useState([{ key: 1, name: null, type: null, variant: null }]); + + useEffect(() => { + onSelect("addProduct", productFieldData); + }, [productFieldData]); + + const addMoreField = () => { + setProductFieldData((prev) => [ + ...prev, + { + key: prev.length + 1, + name: null, + type: null, + variant: null, + }, + ]); + }; + + const deleteProductField = (index) => { + setProductFieldData((prev) => { + const temp = prev.filter((i) => i.key !== index); + return temp.map((i, n) => ({ ...i, key: n + 1 })); + }); + }; + + const handleUpdateField = (data, target, index) => { + setProductFieldData((prev) => { + return prev.map((i) => { + if (i.key === index) { + return { + ...i, + [target]: data, + }; + } + return { + ...i, + }; + }); + }); + }; + + return ( + +
{t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_HEADER`)}
+

+ {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_PRE_TEXT`)} {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_BOLD_TEXT`)} + {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_POST_TEXT`)} +

+ {productFieldData?.map((field, index) => { + return ( + +
+ Product {field?.key} + {productFieldData?.length > 1 && ( +
deleteProductField(field.key)} + style={{ + cursor: "pointer", + fontWeight: "600", + marginLeft: "1rem", + fontSize: "1rem", + color: PRIMARY_COLOR, + display: "flex", + gap: "0.5rem", + alignItems: "center", + marginTop: "1rem", + }} + > + + {t(`CAMPAIGN_DELETE_ROW_TEXT`)} +
+ )} +
+ +
+ {`${t("HCM_PRODUCT_NAME")}`} + * +
+ handleUpdateField(event.target.value, "name", field.key)} + /> +
+ +
+ {`${t("HCM_PRODUCT_TYPE")}`} + * +
+ { + handleUpdateField(value, "type", field.key); + }} + /> +
+ +
+ {`${t("HCM_PRODUCT_VARIANT")}`} + * +
+ handleUpdateField(event.target.value, "variant", field?.key)} + /> +
+
+ ); + })} + + ))} + + ); +}; + +const CycleDataPreview = ({ data, items, index, errors, onErrorClick, cardErrors }) => { + const { t } = useTranslation(); + const [deliveryData, setDeliveryData] = useState(data?.deliveries); + const [activeTab, setActiveTab] = useState(1); + + useEffect(() => { + setDeliveryData(data?.deliveries); + }, [data?.deliveries]); + + const handleTabChange = (tabIndex, index) => { + setDeliveryData((prev) => { + return prev.map((i) => { + if (i.deliveryIndex == tabIndex) { + return { + ...i, + active: true, + }; + } else { + return { + ...i, + active: false, + }; + } + }); + }); + }; + // return null; + return ( + <> + {cardErrors?.map((i) => ( + ]} + /> + ))} + {/* {i.error ? i.error : i.message)} */} +
+ {data?.startDate && ( + + )} + {data?.endDate && ( + + )} +
+ +
+ + + + {deliveryData + .find((i) => i.active === true) + ?.deliveryRules?.map((rules, ruleIndex) => { + return ( + + {rules?.attributes?.length > 0 && ( + + )} + {rules?.products?.length > 0 && ( + + )} + + ); + })} + + {/* + {item?.conditions?.length > 0 && ( + + )} + {item?.products?.length > 0 && ( + + )} + */} + + ); +}; + +export default CycleDataPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js new file mode 100644 index 00000000000..515b25191d9 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js @@ -0,0 +1,143 @@ +import { Card, LabelFieldPair, Row } from "@egovernments/digit-ui-react-components"; +import React, { Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import DetailsTable from "./DetailsTable"; + +function mergeObjects(item) { + const arr = item?.conditions; + const mergedArr = []; + const mergedAttributes = new Set(); + + arr.forEach((obj) => { + if (!mergedAttributes.has(obj.attribute)) { + const sameAttrObjs = arr.filter((o) => o.attribute === obj.attribute); + + if (sameAttrObjs.length > 1) { + const fromValue = Math.min(...sameAttrObjs.map((o) => o.value)); + const toValue = Math.max(...sameAttrObjs.map((o) => o.value)); + + mergedArr.push({ + fromValue, + toValue, + value: fromValue > 0 && toValue > 0 ? `${fromValue} to ${toValue}` : null, + operator: "IN_BETWEEN", + attribute: obj.attribute, + }); + + mergedAttributes.add(obj.attribute); + } else { + mergedArr.push(obj); + } + } + }); + + return { ...item, conditions: mergedArr }; +} + +const CycleDetaisPreview = ({ data, items, index }) => { + const { t } = useTranslation(); + const item = mergeObjects(items); + + return ( + <> + + + {/* + {`${t("CYCLE_NUMBER")}`} + {item?.cycleNumber} + + + {`${t("DELIVERY_NUMBER")}`} + {item?.deliveryNumber} + */} + {item?.startDate || item?.endDate ? ( + +
+

+ {t(`CYCLE`)} {item?.cycleNumber} +

+
+ {item?.startDate && ( + + )} + {item?.endDate && ( + + )} +
+ ) : null} + + + {item?.conditions?.length > 0 && ( + + )} + {item?.products?.length > 0 && ( + + )} + + + ); +}; + +export default CycleDetaisPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js new file mode 100644 index 00000000000..5c6e01fcc22 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js @@ -0,0 +1,76 @@ +import React, { Fragment } from "react"; +import { useTable } from "react-table"; +import { useTranslation } from "react-i18next"; +import { CardLabel, CardSubHeader } from "@egovernments/digit-ui-react-components"; + +const DetailsTable = ({ className = "", columnsData, rowsData, summaryRows, cardHeader }) => { + const { t } = useTranslation(); + + const columns = React.useMemo(() => columnsData, [t]); + + const data = React.useMemo(() => { + const temp = rowsData.map((i) => ({ + ...i, + operator: t(i?.operator), + attribute: i?.attribute ? t(`CAMPAIGN_ATTRIBUTE_${i?.attribute?.toUpperCase()}`) : "", + })); + return temp; + }, [rowsData]); + + const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ + columns, + data, + }); + + return ( + <> + {cardHeader && ( + + {cardHeader?.value} + + )} +
+ + + {headerGroups.map((headerGroup) => ( + + {headerGroup.headers.map((column) => ( + + ))} + + ))} + + + + {rows.map((row) => { + prepareRow(row); + return ( + + {row.cells.map((cell) => ( + + ))} + + ); + })} + + {summaryRows && ( + + {summaryRows.map((cell, index) => ( + + ))} + + )} + +
+ {column.render("Header")} +
+ {cell.render("Cell")} +
+ {index === 4 ? {cell} : cell} +
+
+ + ); +}; + +export default DetailsTable; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js new file mode 100644 index 00000000000..9b61bf67136 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js @@ -0,0 +1,29 @@ +import React from "react"; +export const DocumentIcon = ({ styles = {}, className, fill = "#D4351C" }) => ( + + + + + + + + + + + + + + + + + + + + +); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js new file mode 100644 index 00000000000..89d7b574032 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js @@ -0,0 +1,47 @@ +import React, { useState } from "react"; + +const PlusMinusInput = (props, customProps) => { + let count = props?.defaultValues || 1; + + function incrementCount() { + if (count >= 1) { + count = count + 1; + props.onSelect(count); + } else { + count = 1; + props.onSelect(count); + } + } + function decrementCount() { + if (count > 1) { + count = count - 1; + props.onSelect(count); + } else { + count = 1; + props.onSelect(count); + } + } + + return ( + +
+ + + +
+
+ ); +}; + +export default PlusMinusInput; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js new file mode 100644 index 00000000000..b04159181a6 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js @@ -0,0 +1,16 @@ +import React from "react"; +import { Close } from "@egovernments/digit-ui-react-components"; + +const RemoveableTagNew = ({ text = {}, onClick, extraStyles, disabled = false }) => ( +
+ {text?.label && {`${text?.label} :`}} + + {text?.value} + + + + +
+); + +export default RemoveableTagNew; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js new file mode 100644 index 00000000000..239cf948ee0 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js @@ -0,0 +1,542 @@ +import React, { useEffect, useState, Fragment, useMemo } from "react"; +import { CardText, LabelFieldPair, Card, Header, CardLabel, LoaderWithGap } from "@egovernments/digit-ui-react-components"; +import { useTranslation } from "react-i18next"; +import { InfoCard, MultiSelectDropdown, PopUp, Button, Toast } from "@egovernments/digit-ui-components"; +import { mailConfig } from "../configs/mailConfig"; +/** + * The function `SelectingBoundaries` in JavaScript handles the selection of boundaries based on + * hierarchy data and allows users to choose specific boundaries within the hierarchy. + * @returns The `SelectingBoundaries` component is being returned. It consists of JSX elements + * including Cards, Headers, Dropdowns, MultiSelectDropdowns, and InfoCard. The component allows users + * to select hierarchy types and boundaries based on the data fetched from API calls. It also handles + * the selection of boundaries and updates the state accordingly. The component is designed to be + * interactive and user-friendly for selecting boundaries within + */ +function SelectingBoundaries({ onSelect, formData, ...props }) { + const { t } = useTranslation(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const [params, setParams] = useState(props?.props?.dataParams); + const [hierarchy, setHierarchy] = useState(params?.hierarchyType); + const [boundaryType, setBoundaryType] = useState( + props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData ? undefined : null + ); + const [targetedData, setTargetedData] = useState(); + const [boundaryData, setBoundaryData] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || {}); + // const [parentArray, setParentArray] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData.filter(item => item.includeAllChildren).map(item => item.code) || null); + const [parentArray, setParentArray] = useState(null); + const [boundaryTypeDataresult, setBoundaryTypeDataresult] = useState(null); + const [selectedData, setSelectedData] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData || []); + const [parentBoundaryTypeRoot, setParentBoundaryTypeRoot] = useState( + (props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData?.find((item) => item?.isRoot === true) || {}) + ?.boundaryType || null + ); + const [showToast, setShowToast] = useState(null); + const [updatedHierarchy, setUpdatedHierarchy] = useState({}); + const [hierarchyTypeDataresult, setHierarchyTypeDataresult] = useState(params?.hierarchy); + const [executionCount, setExecutionCount] = useState(0); + // State variable to store the lowest hierarchy level + // const [lowestHierarchy, setLowestHierarchy] = useState(null); + const [showPopUp, setShowPopUp] = useState(null); + const [restrictSelection, setRestrictSelection] = useState(null); + const [updateBoundary, setUpdateBoundary] = useState(null); + const [loaderEnabled, setLoaderEnabled] = useState(false); + const { isLoading, data: hierarchyConfig } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }]); + + // const lowestHierarchy = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy; + const lowestHierarchy = useMemo(() => hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy, [hierarchyConfig]); + const lowestChild = hierarchyTypeDataresult?.boundaryHierarchy.filter((item) => item.parentBoundaryType === lowestHierarchy)?.[0]?.boundaryType; + const searchParams = new URLSearchParams(location.search); + const isDraft = searchParams.get("draft"); + + useEffect(() => { + if (!updateBoundary) { + if ( + props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.length > 0 || + props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.length > 0 || + props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.length > 0 + ) { + setRestrictSelection(true); + } + } + }, [props?.props?.sessionData, updateBoundary]); + + useEffect(() => { + if (props?.props?.dataParams) { + setParams(props?.props?.dataParams); + } + }, [props?.props?.dataParams]); + + useEffect(() => { + onSelect("boundaryType", { boundaryData: boundaryData, selectedData: selectedData, updateBoundary: updateBoundary }); + }, [boundaryData, selectedData]); + + useEffect(() => { + setHierarchy(params?.hierarchyType); + }, [params?.hierarchyType]); + + useEffect(() => { + if (params?.hierarchy) { + const sortHierarchy = (hierarchy) => { + const boundaryMap = new Map(); + hierarchy.forEach(item => { + boundaryMap.set(item.boundaryType, item); + }); + + const sortedHierarchy = []; + let currentType = null; + + while (sortedHierarchy.length < hierarchy.length) { + for (let i = 0; i < hierarchy.length; i++) { + if (hierarchy[i].parentBoundaryType === currentType) { + sortedHierarchy.push(hierarchy[i]); + currentType = hierarchy[i].boundaryType; + break; + } + } + } + + return sortedHierarchy; + }; + + const sortedHierarchy = sortHierarchy(params.hierarchy.boundaryHierarchy); + setHierarchyTypeDataresult({ + ...params.hierarchy, + boundaryHierarchy: sortedHierarchy + }); + } + }, [params?.hierarchy]); + + useEffect(() => { + if (executionCount < 5) { + onSelect("boundaryType", { boundaryData: boundaryData, selectedData: selectedData, updateBoundary: updateBoundary }); + setExecutionCount((prevCount) => prevCount + 1); + } + }); + + useEffect(() => { + setBoundaryData( + props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData + ? props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData + : {} + ); + setSelectedData( + props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData + ? props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData + : [] + ); + }, [props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType]); + + const closeToast = () => { + setShowToast(null); + }; + + useEffect(() => { + if (hierarchyTypeDataresult) { + const boundaryDataObj = {}; + hierarchyTypeDataresult?.boundaryHierarchy?.forEach((boundary) => { + boundaryDataObj[boundary?.boundaryType] = []; + }); + if (!props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || Object.keys(boundaryData).length === 0) { + setBoundaryData(boundaryDataObj); + } + const boundaryWithTypeNullParent = hierarchyTypeDataresult?.boundaryHierarchy?.find((boundary) => boundary?.parentBoundaryType === null); + // Set the boundary type with null parentBoundaryType + if (boundaryWithTypeNullParent) { + if (!props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || Object.keys(boundaryData).length === 0) { + setBoundaryType(boundaryWithTypeNullParent?.boundaryType); + } + setParentBoundaryTypeRoot(boundaryWithTypeNullParent?.boundaryType); + } + createHierarchyStructure(hierarchyTypeDataresult); + } + }, [hierarchyTypeDataresult]); + + function createHierarchyStructure(hierarchyTypeDataresult) { + const hierarchyStructure = {}; + + // Recursive function to gather all descendants for a given boundary type + function gatherDescendants(boundaryType) { + const descendants = []; + hierarchyTypeDataresult; + + // Find all children for the current boundary type + const children = hierarchyTypeDataresult?.boundaryHierarchy?.filter((item) => item?.parentBoundaryType === boundaryType); + + // Recursively gather descendants for each child + children.forEach((child) => { + const childBoundaryType = child?.boundaryType; + const childDescendants = gatherDescendants(childBoundaryType); + descendants.push(childBoundaryType, ...childDescendants); + }); + + return descendants; + } + + // Iterate through the boundaryHierarchy array to populate hierarchyStructure + hierarchyTypeDataresult?.boundaryHierarchy?.forEach((item) => { + const boundaryType = item?.boundaryType; + const descendants = gatherDescendants(boundaryType); + + hierarchyStructure[boundaryType] = descendants; + }); + + setUpdatedHierarchy(hierarchyStructure); + } + + const newData = []; + const fetchBoundaryTypeData = async () => { + if (boundaryType === undefined || boundaryType === lowestChild) { + // Do nothing if boundaryType is undefined + return; + } + if (parentArray === null) { + const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ + url: "/boundary-service/boundary-relationships/_search", + params: { + tenantId: tenantId, + hierarchyType: hierarchy, + boundaryType: boundaryType, + parent: null, + }, + body: {}, + }); + // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); + const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; + setBoundaryTypeDataresult([{ parentCode: null, boundaryTypeData: boundaryTypeData }]); + // closeToast(); + } else { + // for (const parentCode of parentArray) { + // const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ + // url: "/boundary-service/boundary-relationships/_search", + // params: { + // tenantId: tenantId, + // hierarchyType: hierarchy, + // boundaryType: boundaryType, + // parent: parentCode, + // }, + // body: {}, + // }); + // // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); + // setLoaderEnabled(true); + // const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; + // newData.push({ parentCode, boundaryTypeData }); + // } + setLoaderEnabled(true); + const temp = await Digit.Hooks.campaign.useParallelSearch({ + parentArray: parentArray, + tenantId: tenantId, + boundaryType: boundaryType, + hierarchy: hierarchy, + targetedData: targetedData, + }); + const newDataArray = [...newData, ...temp]; + setBoundaryTypeDataresult(newDataArray); + setTimeout(() => { + setLoaderEnabled(false); + }, 100); + // closeToast(); + } + }; + + useEffect(() => { + fetchBoundaryTypeData(); + }, [boundaryType, parentArray, selectedData]); + + useEffect(() => { + if (boundaryTypeDataresult) { + if (boundaryType !== undefined) { + const updatedBoundaryData = { + ...boundaryData, + [boundaryType]: boundaryTypeDataresult, + }; + setBoundaryData(updatedBoundaryData); + } else { + const updatedBoundaryData = { + ...boundaryData, + [boundaryTypeDataresult?.[0]?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.[0]?.boundaryType]: boundaryTypeDataresult, + }; + setBoundaryData(updatedBoundaryData); + } + } + }, [boundaryTypeDataresult]); + + const checkDataPresent = ({ action }) => { + if (action === false) { + setShowPopUp(false); + setUpdateBoundary(true); + setRestrictSelection(false); + return; + } + if (action === true) { + setShowPopUp(false); + setUpdateBoundary(false); + return; + } + }; + + const handleBoundaryChange = (data, boundary) => { + setTargetedData(boundary?.boundaryType); + if ( + !updateBoundary && + restrictSelection && + (props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.length > 0 || + props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.length > 0 || + props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.length > 0) + ) { + setShowPopUp(true); + return; + } + if (!data || data.length === 0) { + const check = updatedHierarchy[boundary?.boundaryType]; + + if (check) { + const typesToRemove = [boundary?.boundaryType, ...check]; + const updatedSelectedData = selectedData?.filter((item) => !typesToRemove?.includes(item?.type)); + const updatedBoundaryData = { ...boundaryData }; + + typesToRemove.forEach((type) => { + if (type !== boundary?.boundaryType && updatedBoundaryData?.hasOwnProperty(type)) { + updatedBoundaryData[type] = []; + } + }); + if (!_.isEqual(selectedData, updatedSelectedData)) { + setSelectedData(updatedSelectedData); + } + setBoundaryData(updatedBoundaryData); + } + return; + } + + let res = []; + data && + data?.map((ob) => { + res.push(ob?.[1]); + }); + + // const transformedRes = res?.map((item) => ({ + // code: item.code, + // type: item.type || item.boundaryType, + // isRoot: item.boundaryType === parentBoundaryTypeRoot, + // includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, + // parent: item?.parent, + // })); + + let transformedRes = []; + if (!isDraft) { + transformedRes = res?.map((item) => ({ + code: item.code, + type: item.type || item.boundaryType, + isRoot: item.boundaryType === parentBoundaryTypeRoot, + includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, + parent: item?.parent, + })); + } else { + // transformedRes = selectedData.filter((item) => item?.type === boundary?.boundaryType) + const filteredData = selectedData.filter((item) => item?.type === boundary?.boundaryType); + if (filteredData.length === 0) { + // If no selected data for the particular boundary type, run the transformation logic + transformedRes = res?.map((item) => ({ + code: item.code, + type: item.type || item.boundaryType, + isRoot: item.boundaryType === parentBoundaryTypeRoot, + includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, + parent: item?.parent, + })); + } else { + transformedRes = filteredData; + } + } + + const newBoundaryType = transformedRes?.[0]?.type; + const existingBoundaryType = selectedData?.length > 0 ? selectedData?.[0]?.type : null; + if (existingBoundaryType === newBoundaryType) { + // Update only the data for the specific boundaryType + const flattenedRes = transformedRes.flat(); + const updatedSelectedData = selectedData + ?.map((item) => { + if (item.type === newBoundaryType) { + return transformedRes?.flat(); + } else { + return item; + } + }) + .flat(); + if (!_.isEqual(selectedData, updatedSelectedData)) { + setSelectedData(updatedSelectedData); + } + } else { + // Update only the data for the new boundaryType + const mergedData = [...selectedData?.filter((item) => item?.type !== newBoundaryType), ...transformedRes]; + + // Filter out items with undefined type + const filteredData = mergedData?.filter( + (item, index, self) => item?.type !== undefined && index === self?.findIndex((t) => t?.code === item?.code) + ); + + // Filter out items whose parent is not present in the array + + const updatedSelectedData = []; + const addChildren = (item) => { + updatedSelectedData.push(item); + const children = filteredData.filter((child) => child.parent === item.code); + children.forEach((child) => addChildren(child)); + }; + filteredData.filter((item) => item.isRoot).forEach((rootItem) => addChildren(rootItem)); + if (!_.isEqual(selectedData, updatedSelectedData)) { + setSelectedData(updatedSelectedData); + } + } + const parentBoundaryEntry = hierarchyTypeDataresult + ? hierarchyTypeDataresult?.boundaryHierarchy?.find( + (e) => e?.parentBoundaryType === res?.[0]?.boundaryType || e?.parentBoundaryType === res?.[0]?.type + ) + : null; + setBoundaryType(parentBoundaryEntry?.boundaryType); + const codes = res?.map((item) => item?.code); + if (JSON.stringify(codes) !== JSON.stringify(parentArray)) { + setParentArray(codes); + } + }; + + return ( + <> + {loaderEnabled && } + +
+
{t(`CAMPAIGN_SELECT_BOUNDARY`)}
+ {t(`CAMPAIGN_SELECT_BOUNDARIES_DESCRIPTION`)} + {hierarchyTypeDataresult?.boundaryHierarchy + .filter((boundary, index, array) => { + // Find the index of the lowest hierarchy + const lowestIndex = array.findIndex((b) => b.boundaryType === lowestHierarchy); + // Include only those boundaries that are above or equal to the lowest hierarchy + return index <= lowestIndex; + }) + .map((boundary, index) => + boundary?.parentBoundaryType == null ? ( + + + {/* {t(`${hierarchy}_${boundary?.boundaryType}`?.toUpperCase())} */} + {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} + + * + +
+ item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary)?.flat() || [] + } + optionsKey={"code"} + selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} + onSelect={(value) => { + handleBoundaryChange(value, boundary); + }} + /> +
+
+ ) : ( + + + {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} + * + +
+ ({ + code: item?.parentCode, + options: + item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.map((child) => ({ + code: child?.code, + type: child?.boundaryType, + parent: item?.parentCode, + })) || [], + })) || [] + } + optionsKey={"code"} + onSelect={(value) => { + handleBoundaryChange(value, boundary); + }} + selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} + addCategorySelectAllCheck={true} + addSelectAllCheck={true} + variant="nestedmultiselect" + /> +
+
+ ) + )} +
+
+ + {t("HCM_BOUNDARY_INFO ")} + + {mailConfig?.mailId} + + , + ]} + label={"Info"} + /> + {showPopUp && ( + + {t("ES_CAMPAIGN_UPDATE_BOUNDARY_MODAL_TEXT") + " "} + , + ]} + onOverlayClick={() => { + setShowPopUp(false); + }} + footerChildren={[ + + ))} + + ); +}; + +const TabContent = ({ activeSubTab, subTabCount = 3, onSubTabChange, project }) => { + const { campaignData, dispatchCampaignData } = useContext(CycleContext); + const { t } = useTranslation(); + + return ( + + +
+ {t(`CAMPAIGN_TAB_TEXT`)} + {t(`CAMPAIGN_TAB_SUB_TEXT_${project?.code ? project?.code?.toUpperCase() : project?.toUpperCase()}`)} +
+ {/* Add content specific to each tab as needed */} + , + + {t(`CAMPAIGN_TAB_INFO_TEXT_${project?.code ? project?.code?.toUpperCase() : project?.toUpperCase()}`)} + + ]} + label={"Info"} + /> +
+ ); +}; + +const SubTabs = ({ onSubTabChange }) => { + const { campaignData, dispatchCampaignData } = useContext(CycleContext); + const { t } = useTranslation(); + + return ( +
+ {campaignData + ?.find((i) => i?.active === true) + ?.deliveries.map((_, index) => ( + + ))} +
+ ); +}; + +const MultiTab = ({ tabCount = 3, subTabCount = 2 }) => { + const [activeTab, setActiveTab] = useState(0); + const [activeSubTab, setActiveSubTab] = useState(0); + const { campaignData, dispatchCampaignData } = useContext(CycleContext); + const { t } = useTranslation(); + const tempSession = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + const handleTabChange = (tabIndex, index) => { + dispatchCampaignData({ + type: "TAB_CHANGE_UPDATE", + payload: { tabIndex: tabIndex, index: index }, // Your updated campaign data + }); + setActiveTab(index); + setActiveSubTab(0); // Reset sub-tab when changing the main tab + }; + + const handleSubTabChange = (subTabIndex, itemIndex) => { + dispatchCampaignData({ + type: "SUBTAB_CHANGE_UPDATE", + payload: { subTabIndex: subTabIndex }, // Your updated campaign data + }); + }; + + return ( + <> +
+ {t( + `CAMPAIGN_PROJECT_${ + tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code + ? tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code?.toUpperCase() + : tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.toUpperCase() + }` + )} +
+ +
+
+ +
+ + +
+ + ); +}; + +export default MultiTab; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js new file mode 100644 index 00000000000..ebdf2c5088f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js @@ -0,0 +1,531 @@ +import React, { createContext, useContext, useEffect, useReducer, useState } from "react"; +import MultiTab from "./MultiTabcontext"; +import { Loader } from "@egovernments/digit-ui-react-components"; +// import { deliveryConfig } from "../../../configs/deliveryConfig"; + +const CycleContext = createContext(); + +function makeSequential(jsonArray, keyName) { + return jsonArray.map((item, index) => ({ + ...item, + [keyName]: index + 1, + })); +} + +function DeliverySetup({ onSelect, config, formData, control, tabCount = 2, subTabCount = 3, ...props }) { + // Campaign Tab Skeleton function + const [cycleData, setCycleData] = useState(config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure); + const saved = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule; + const selectedProjectType = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_TYPE?.projectType?.code; + const tenantId = Digit.ULBService.getCurrentTenantId(); + const searchParams = new URLSearchParams(location.search); + const activeCycle = searchParams.get("activeCycle"); + const { isLoading: deliveryConfigLoading, data: filteredDeliveryConfig } = Digit.Hooks.useCustomMDMS( + tenantId, + "HCM-ADMIN-CONSOLE", + [{ name: "deliveryConfig" }], + { + select: (data) => { + const temp = data?.["HCM-ADMIN-CONSOLE"]?.deliveryConfig; + return temp?.find((i) => i?.projectType === selectedProjectType); + // return deliveryConfig?.find((i) => i?.projectType === selectedProjectType); + }, + } + ); + // const [filteredDeliveryConfig, setFilteredDeliveryConfig] = useState(deliveryConfig?.find((i) => i?.projectType === selectedProjectType)); + // useEffect(() => { + // if (!deliveryConfigLoading) { + // const temp = deliveryConfig?.find((i) => i?.projectType === selectedProjectType); + // setFilteredDeliveryConfig(temp); + // } + // }, [deliveryConfigLoading, filteredDeliveryConfig]); + // const filteredDeliveryConfig = deliveryConfig.find((i) => i.projectType === selectedProjectType); + useEffect(() => { + setCycleData(config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure); + }, [config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure]); + + const generateTabsData = (tabs, subTabs) => { + if (!saved || saved?.length === 0) { + return [...Array(tabs)].map((_, tabIndex) => ({ + cycleIndex: `${tabIndex + 1}`, + active: activeCycle == tabIndex + 1 ? true : tabIndex === 0 ? true : false, + deliveries: [...Array(subTabs || 1)].map((_, subTabIndex) => ({ + deliveryIndex: `${subTabIndex + 1}`, + active: subTabIndex === 0 ? true : false, + deliveryRules: + filteredDeliveryConfig?.projectType === "LLIN-mz" + ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { + return { + ruleKey: index + 1, + delivery: {}, + attributes: item?.attributeConfig + ? item?.attributeConfig?.map((i, c) => { + if (i?.operatorValue === "IN_BETWEEN") { + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + toValue: i?.fromValue, + fromValue: i?.toValue, + }; + } + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + }; + }) + : [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: item?.productConfig + ? item?.productConfig?.map((i, c) => ({ + ...i, + })) + : [], + }; + }) + : filteredDeliveryConfig && filteredDeliveryConfig?.deliveryConfig?.[subTabIndex] + ? filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig?.map((item, index) => { + if (item) { + return { + ruleKey: index + 1, + delivery: {}, + deliveryType: item?.deliveryType, + attributes: item?.attributeConfig + ? item?.attributeConfig?.map((i, c) => { + if (i?.operatorValue === "IN_BETWEEN") { + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + toValue: i?.fromValue, + fromValue: i?.toValue, + }; + } + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + }; + }) + : [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: item?.productConfig + ? item?.productConfig?.map((i, c) => ({ + ...i, + })) + : [], + }; + } else { + return { + ruleKey: index + 1, + delivery: {}, + deliveryType: null, + attributes: [{ key: 1, attribute: null, operator: null, value: "" }], + products: [], + }; + } + }) + : [ + { + ruleKey: 1, + delivery: {}, + attributes: + filteredDeliveryConfig && filteredDeliveryConfig?.attributeConfig + ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + })) + : // : filteredDeliveryConfig?.projectType === "LLIN-mz" + // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ key: c + 1, attribute: i.attrValue, operator: null, value: "" })) + [{ key: 1, attribute: null, operator: null, value: "" }], + products: [], + }, + ], + })), + })); + } + // if no change + if (saved && saved?.length == tabs && saved?.[0]?.deliveries?.length === subTabs) { + return saved.map((i, n) => { + return { + ...i, + active: activeCycle ? (activeCycle == n + 1 ? true : false) : n === 0 ? true : false, + }; + }); + } + // if cycle number decrease + if (saved?.length > tabs) { + // const temp = saved; + saved.splice(tabs); + // return temp; + } + // if cycle number increase + if (tabs > saved?.length) { + // const temp = saved; + for (let i = saved.length + 1; i <= tabs; i++) { + const newIndex = i.toString(); + saved.push({ + cycleIndex: newIndex, + active: false, + deliveries: [...Array(subTabs || 1)].map((_, subTabIndex) => ({ + deliveryIndex: `${subTabIndex + 1}`, + active: subTabIndex === 0, + deliveryRules: + filteredDeliveryConfig?.projectType === "LLIN-mz" + ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { + return { + ruleKey: index + 1, + delivery: {}, + attributes: item?.attributeConfig + ? item?.attributeConfig?.map((i, c) => { + if (i?.operatorValue === "IN_BETWEEN") { + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + toValue: i?.fromValue, + fromValue: i?.toValue, + }; + } + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + }; + }) + : [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: item?.productConfig + ? item?.productConfig?.map((i, c) => ({ + ...i, + })) + : [], + }; + }) + : filteredDeliveryConfig && filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig + ? filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig?.map((item, index) => { + if (item) { + return { + ruleKey: index + 1, + delivery: {}, + deliveryType: item?.deliveryType, + attributes: item?.attributeConfig + ? item?.attributeConfig?.map((i, c) => { + if (i?.operatorValue === "IN_BETWEEN") { + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + toValue: i?.fromValue, + fromValue: i?.toValue, + }; + } + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + }; + }) + : [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: item?.productConfig + ? item?.productConfig?.map((i, c) => ({ + ...i, + })) + : [], + }; + } else { + return { + ruleKey: index + 1, + delivery: {}, + deliveryType: null, + attributes: [{ key: 1, attribute: null, operator: null, value: "" }], + products: [], + }; + } + }) + : [ + { + ruleKey: 1, + delivery: {}, + deliveryType: null, + attributes: + // filteredDeliveryConfig?.projectType === "MR-DN" + // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ + // key: c + 1, + // attribute: { code: i?.attrValue }, + // operator: { code: i?.operatorValue }, + // value: i?.value, + // })) + // : filteredDeliveryConfig?.projectType === "LLIN-mz" + // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ + // key: c + 1, + // attribute: i.attrValue, + // operator: null, + // value: "", + // })) + // : + [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: [], + }, + ], + })), + }); + } + // return temp; + } + // if delivery number decrease + + saved.forEach((cycle) => { + // Remove deliveries if there are more deliveries than the specified number + if (cycle.deliveries.length > subTabs) { + cycle.deliveries.splice(subTabs); + } + + // Add deliveries if there are fewer deliveries than the specified number + if (subTabs > cycle.deliveries.length) { + for (let i = cycle.deliveries.length + 1; i <= subTabs; i++) { + const newIndex = i.toString(); + cycle.deliveries.push({ + deliveryIndex: newIndex, + active: false, + deliveryRules: + filteredDeliveryConfig?.projectType === "LLIN-mz" + ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { + return { + ruleKey: index + 1, + delivery: {}, + attributes: item?.attributeConfig + ? item?.attributeConfig?.map((i, c) => { + if (i?.operatorValue === "IN_BETWEEN") { + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + toValue: i?.fromValue, + fromValue: i?.toValue, + }; + } + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + }; + }) + : [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: item?.productConfig + ? item?.productConfig?.map((i, c) => ({ + ...i, + })) + : [], + }; + }) + : [ + { + ruleKey: 1, + delivery: {}, + attributes: [{ key: 1, attribute: null, operator: null, value: "" }], + products: [], + }, + ], + }); + } + } + }); + + return saved; + // if delivery number increase + + //if no above case + }; + + // Reducer function + const campaignDataReducer = (state, action) => { + switch (action.type) { + case "GENERATE_CAMPAIGN_DATA": + return generateTabsData(action.cycle, action.deliveries); + case "UPDATE_CAMPAIGN_DATA": + const changeUpdate = state.map((i) => { + if (i.active) { + const activeDelivery = i.deliveries.find((j) => j.active === true); + if (activeDelivery) { + return { + ...i, + deliveries: i.deliveries.map((j) => ({ + ...j, + deliveryRules: j.active ? action.payload.currentDeliveryRules : j.deliveryRules, + })), + }; + } + } + return i; + }); + return changeUpdate; + case "TAB_CHANGE_UPDATE": + const temp = state.map((i) => ({ + ...i, + active: i.cycleIndex == action.payload.tabIndex ? true : false, + })); + return temp; + // return action.payload; + case "SUBTAB_CHANGE_UPDATE": + const tempSub = state.map((camp, index) => { + if (camp.active === true) { + return { + ...camp, + deliveries: camp.deliveries.map((deliver) => ({ + ...deliver, + active: deliver.deliveryIndex == action.payload.subTabIndex ? true : false, + })), + }; + } + return camp; + }); + return tempSub; + case "ADD_DELIVERY_RULE": + const updatedDeliveryRules = [ + ...action.payload.currentDeliveryRules, + { + ruleKey: action.payload.currentDeliveryRules.length + 1, + delivery: {}, + attributes: [{ key: 1, attribute: null, operator: null, value: "" }], + products: [], + }, + ]; + const updatedData = state.map((i) => { + if (i.active) { + const activeDelivery = i.deliveries.find((j) => j.active); + if (activeDelivery) { + return { + ...i, + deliveries: i.deliveries.map((j) => ({ + ...j, + deliveryRules: j.active ? updatedDeliveryRules : j.deliveryRules, + })), + }; + } + } + return i; + }); + return updatedData; + case "REMOVE_DELIVERY_RULE": + const updatedDeleted = state.map((i) => { + if (i.active) { + const activeDelivery = i.deliveries.find((j) => j.active); + const w = makeSequential( + activeDelivery.deliveryRules.filter((j) => j.ruleKey != action.payload.item.ruleKey), + "ruleKey" + ); + if (activeDelivery) { + return { + ...i, + deliveries: i.deliveries.map((j) => ({ + ...j, + deliveryRules: j.active ? w : j.deliveryRules, + })), + }; + } + } + return i; + }); + return updatedDeleted; + case "UPDATE_DELIVERY_RULE": + return action.payload; + case "ADD_ATTRIBUTE": + return action.payload; + case "REMOVE_ATTRIBUTE": + return action.payload; + case "UPDATE_ATTRIBUTE": + return action.payload; + case "ADD_PRODUCT": + const prodTemp = action.payload.productData.map((i) => ({ ...i, value: i?.value?.id, name: i?.value?.displayName })); + const updatedState = state.map((cycle) => { + if (cycle.active) { + const updatedDeliveries = cycle.deliveries.map((dd) => { + if (dd.active) { + const updatedRules = dd.deliveryRules.map((rule) => { + if (rule.ruleKey === action.payload.delivery.ruleKey) { + return { + ...rule, + products: [...rule.products, ...prodTemp], + }; + } + return rule; + }); + return { + ...dd, + deliveryRules: updatedRules, + }; + } + return dd; + }); + return { + ...cycle, + deliveries: updatedDeliveries, + }; + } + return cycle; + }); + return updatedState; + case "REMOVE_PRODUCT": + return action.payload; + case "UPDATE_PRODUCT": + return action.payload; + default: + return state; + } + }; + + const [campaignData, dispatchCampaignData] = useReducer( + campaignDataReducer, + generateTabsData(cycleData?.cycleConfgureDate?.cycle, cycleData?.cycleConfgureDate?.deliveries) + ); + const [executionCount, setExecutionCount] = useState(0); + + useEffect(() => { + dispatchCampaignData({ + type: "GENERATE_CAMPAIGN_DATA", + cycle: cycleData?.cycleConfgureDate?.cycle, + deliveries: cycleData?.cycleConfgureDate?.deliveries, + }); + }, [cycleData]); + + useEffect(() => { + onSelect("deliveryRule", campaignData); + }, [campaignData]); + + useEffect(() => { + if (executionCount < 5) { + onSelect("deliveryRule", campaignData); + setExecutionCount((prevCount) => prevCount + 1); + } + }); + + if (deliveryConfigLoading) { + return ; + } + return ( + + + + ); +} + +export default DeliverySetup; +export { CycleContext }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js new file mode 100644 index 00000000000..2353f85fc50 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js @@ -0,0 +1,102 @@ +import React, { useEffect } from "react"; +import { Switch, useLocation } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { PrivateRoute, AppContainer, BreadCrumb } from "@egovernments/digit-ui-react-components"; +// import CampaignHeader from "../../components/CampaignHeader"; +import SetupCampaign from "./SetupCampaign"; +import SelectingBoundaries from "../../components/SelectingBoundaries"; + +/** + * The CampaignBreadCrumb function generates breadcrumb navigation for a campaign setup page in a React + * application. + * @returns The CampaignBreadCrumb component is returning a BreadCrumb component with the specified + * crumbs array and spanStyle prop. The crumbs array contains two objects with path, content, and show + * properties for each breadcrumb item. The spanStyle prop is set to { maxWidth: "min-content" }. + */ +const CampaignBreadCrumb = ({ location, defaultPath }) => { + const { t } = useTranslation(); + const search = useLocation().search; + const pathVar = location.pathname.replace(defaultPath + "/", "").split("?")?.[0]; + + const crumbs = [ + { + path: `/${window?.contextPath}/employee`, + content: t("CAMPAIGN_HOME"), + show: true, + }, + { + path: pathVar === "my-campaign" ? "" : `/${window?.contextPath}/employee/campaign/my-campaign`, + content: t("MY_CAMPAIGN"), + show: pathVar === "my-campaign" ? true : false, + }, + { + path: pathVar === "setup-campaign" ? "" : `/${window?.contextPath}/employee/campaign/setup-campaign`, + content: t("CREATE_NEW_CAMPAIGN"), + show: pathVar === "setup-campaign" ? true : false, + }, + ]; + + return ; +}; + +/** + * The `App` function in JavaScript defines a component that handles different routes and renders + * corresponding components based on the path provided. + * @returns The `App` component is returning a JSX structure that includes a `div` with a className of + * "wbh-header-container" containing a `CampaignBreadCrumb` component and a `Switch` component. Inside + * the `Switch` component, there are several `PrivateRoute` components with different paths and + * corresponding components such as `UploadBoundaryData`, `CycleConfiguration`, `DeliveryRule`, ` + */ +const App = ({ path, BOUNDARY_HIERARCHY_TYPE }) => { + const location = useLocation(); + const UploadBoundaryData = Digit?.ComponentRegistryService?.getComponent("UploadBoundaryData"); + const CycleConfiguration = Digit?.ComponentRegistryService?.getComponent("CycleConfiguration"); + const DeliveryRule = Digit?.ComponentRegistryService?.getComponent("DeliveryRule"); + const MyCampaign = Digit?.ComponentRegistryService?.getComponent("MyCampaign"); + const CampaignSummary = Digit?.ComponentRegistryService?.getComponent("CampaignSummary"); + const Response = Digit?.ComponentRegistryService?.getComponent("Response"); + const AddProduct = Digit?.ComponentRegistryService?.getComponent("AddProduct"); + + useEffect(() => { + if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") { + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); + } + if (window.location.pathname === "/workbench-ui/employee/campaign/response") { + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); + } + return () => { + if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") { + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); + } + }; + }, []); + return ( + +
+ {window?.location?.pathname === "/workbench-ui/employee/campaign/add-product" || + window?.location?.pathname === "/workbench-ui/employee/campaign/response" ? null : ( + + )} + {/* */} +
+ + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + +
+ ); +}; + +export default App; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js new file mode 100644 index 00000000000..5ab880c52cf --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js @@ -0,0 +1,144 @@ +export const TourSteps = { + '/workbench-ui/employee/workbench/manage-master-data':[ + { + content: + 'Welcome to Manage Master Data screen. Here you can search and update any master data that is configured for the logged in user tenant', + target: '.manage-master-wrapper', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Select any module name where the master is present', + target: '.wbh-mdms-module-name', + disableBeacon: true, + placement: 'center', + title:"Manage Master Data" + }, + + { + content: + 'Select any master name where the master is present', + target: '.wbh-mdms-master-name', + disableBeacon: true, + placement: 'center', + title:"Manage Master Data" + }, + ], + '/workbench-ui/employee/workbench/mdms-search-v2':[ + { + content: + 'Welcome to the master data search screen. Here you can search the master data added under this master', + target: '.search-wrapper', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Select any field value and enter the text by which data can be filtered', + target: '.label-field-pair', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Filter the master data by clicking on this search by selecting any field and exact value', + target: '.search-button-wrapper', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'To add new master data under this master click on the Add Master Data button', + target: '.mdms-add-btn', + disableBeacon: true, + placement: 'auto', + title:"Manage Master Data" + }, + + ], + '/workbench-ui/employee/workbench/mdms-add-v2':[ + { + content: + 'Welcome to the master data search screen. Here you can search the master data added under this master', + target: '.field-string', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'select the Reference master data', + target: '.form-select ', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Fill all the details by clicking on the Add Master Data', + target: '.submit-bar', + disableBeacon: true, + placement: 'auto', + title:"Manage Master Data" + }, + + ], + '/workbench-ui/employee/workbench/mdms-view':[ + { + content: + 'Welcome to the master data search screen. Here you can search the master data added under this master', + target: '.action-bar-wrap', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'select the Reference master data', + target: '.menu-wrap', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + } + ], + '/workbench-ui/employee/workbench/localisation-search':[ + { + content: + 'Welcome to the master data search screen. Here you can search the master data added under this master', + target: '.search-wrapper', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Select any field value and enter the text by which data can be filtered', + target: '.label-field-pair', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Filter the master data by clicking on this search by selecting any field and exact value', + target: '.search-button-wrapper', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'To add new master data under this master click on the Add Master Data button', + target: '.mdms-add-btn', + disableBeacon: true, + placement: 'auto', + title:"Manage Master Data" + }, + + ], +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js new file mode 100644 index 00000000000..978ea2bfd74 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js @@ -0,0 +1,46 @@ +import axios from "axios"; + +/* Fetching sheet as json object from the API , converting them into blob and downloading it. + * Way to use the function. Just import the funtion downloadExcelWithCustomName and pass the filestoreid and customName you want to download the file. + * Rest this function will take care for you and download it in your system. + * + * Eg. -> + * const handleDownload = (id, name) => { + * downloadExcelWithCustomName({fileStoreId: id, customName: name}); + * } + * + */ + +export const downloadExcelWithCustomName = ({ fileStoreId = null, customName = null }) => { + const downloadExcel = (blob, fileName) => { + const link = document.createElement("a"); + link.href = URL.createObjectURL(blob); + link.download = fileName + ".xlsx"; + document.body.append(link); + link.click(); + link.remove(); + setTimeout(() => URL.revokeObjectURL(link.href), 7000); + }; + + if (fileStoreId) { + axios + .get("/filestore/v1/files/id", { + responseType: "arraybuffer", + headers: { + "Content-Type": "application/json", + Accept: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "auth-token": Digit.UserService.getUser()?.["access_token"], + }, + params: { + tenantId: Digit.ULBService.getCurrentTenantId(), + fileStoreId: fileStoreId, + }, + }) + .then(async (res) => { + downloadExcel( + new Blob([res.data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), + customName ? customName : "download" + ); + }); + } +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js new file mode 100644 index 00000000000..5e308bf82f7 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js @@ -0,0 +1,6 @@ +import _ from "lodash"; +import { downloadExcelWithCustomName } from "./downloadExcel"; + +export default {}; +export { downloadExcelWithCustomName }; +export const PRIMARY_COLOR = "#C84C0E"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json new file mode 100644 index 00000000000..6fcb736c4e5 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json @@ -0,0 +1,62 @@ +{ + "name": "@egovernments/digit-ui-module-hcmmicroplanning", + "version": "0.0.1", + "description": "HCM-Microplanning", + "main": "dist/index.js", + "module": "dist/index.modern.js", + "source": "src/Module.js", + "files": [ + "dist" + ], + "scripts": { + "start": "microbundle-crl watch --no-compress --format modern,cjs", + "build": "microbundle-crl --compress --no-sourcemap --format cjs", + "prepublish": "yarn build" + }, + "peerDependencies": { + "react": "17.0.2", + "react-router-dom": "5.3.0" + }, + "dependencies": { + "@cyntler/react-doc-viewer": "1.10.3", + "@egovernments/digit-ui-components": "0.0.2-beta.2", + "@egovernments/digit-ui-react-components": "1.8.2-beta.4", + "@egovernments/digit-ui-svg-components": "1.0.8", + "@rjsf/core": "5.10.0", + "@rjsf/utils": "5.10.0", + "@rjsf/validator-ajv8": "5.10.0", + "@turf/turf": "^6.5.0", + "ajv": "^8.12.0", + "axios": "^1.6.8", + "chroma-js": "^2.4.2", + "exceljs": "^4.4.0", + "focus-trap-react": "^10.2.3", + "geojson-validation": "^1.0.2", + "jszip": "^3.10.1", + "leaflet": "^1.9.4", + "react": "17.0.2", + "react-date-range": "^1.4.0", + "react-dom": "17.0.2", + "react-drag-drop-files": "^2.3.10", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-joyride": "2.5.5", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "react-select": "5.7.4", + "safe-buffer": "^5.2.1", + "shpjs": "^4.0.4", + "uuid": "^9.0.1", + "xlsx": "0.17.5" + }, + "license": "MIT", + "keywords": [ + "digit", + "egov", + "dpg", + "digit-ui", + "workbench", + "workbench-hcm", + "hcm-microplanning" + ] +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js new file mode 100644 index 00000000000..b27e7b19922 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js @@ -0,0 +1,99 @@ +import { Loader, TourProvider } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useRouteMatch } from "react-router-dom"; +import EmployeeApp from "./pages/employee"; +import { CustomisedHooks } from "./hooks"; +import { UICustomizations } from "./configs/UICustomizations"; +// import WorkbenchCard from "./components/WorkbenchCard"; +import MicroplanningCard from "./components/MicroplanningCard"; +import MicroplanDetails from "./components/MicroplanDetails"; +import { ProviderContext } from "./utils/context"; + +const MicroplanningModule = ({ stateCode, userType, tenants }) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + const { data: BOUNDARY_HIERARCHY_TYPE } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }], { + select: (data) => { + return data?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy; + }, + }); + const moduleCode = ["Microplanning", `boundary-${BOUNDARY_HIERARCHY_TYPE}`, "hcm-admin-schemas"]; + const { path, url } = useRouteMatch(); + const language = Digit.StoreData.getCurrentLanguage(); + const { isLoading, data: store } = Digit.Services.useStore({ + stateCode, + moduleCode, + language, + }); + + if (isLoading) { + return ; + } + + return ( + + + + + + ); +}; + +const componentsToRegister = { + MicroplanningModule, + MicroplanningCard, + MicroplanDetails, + // DigitJSONForm, + // DSSCard: null, // TO HIDE THE DSS CARD IN HOME SCREEN as per workbench + // HRMSCard // Overridden the HRMS card as per workbench +}; + +const overrideHooks = () => { + Object.keys(CustomisedHooks).map((ele) => { + if (ele === "Hooks") { + Object.keys(CustomisedHooks[ele]).map((hook) => { + Object.keys(CustomisedHooks[ele][hook]).map((method) => { + setupHooks(hook, method, CustomisedHooks[ele][hook][method]); + }); + }); + } else if (ele === "Utils") { + Object.keys(CustomisedHooks[ele]).map((hook) => { + Object.keys(CustomisedHooks[ele][hook]).map((method) => { + setupHooks(hook, method, CustomisedHooks[ele][hook][method], false); + }); + }); + } else { + Object.keys(CustomisedHooks[ele]).map((method) => { + setupLibraries(ele, method, CustomisedHooks[ele][method]); + }); + } + }); +}; + +/* To Overide any existing hook we need to use similar method */ +const setupHooks = (HookName, HookFunction, method, isHook = true) => { + window.Digit = window.Digit || {}; + window.Digit[isHook ? "Hooks" : "Utils"] = window.Digit[isHook ? "Hooks" : "Utils"] || {}; + window.Digit[isHook ? "Hooks" : "Utils"][HookName] = window.Digit[isHook ? "Hooks" : "Utils"][HookName] || {}; + window.Digit[isHook ? "Hooks" : "Utils"][HookName][HookFunction] = method; +}; +/* To Overide any existing libraries we need to use similar method */ +const setupLibraries = (Library, service, method) => { + window.Digit = window.Digit || {}; + window.Digit[Library] = window.Digit[Library] || {}; + window.Digit[Library][service] = method; +}; + +/* To Overide any existing config/middlewares we need to use similar method */ +const updateCustomConfigs = () => { + setupLibraries("Customizations", "commonUiConfig", { ...window?.Digit?.Customizations?.commonUiConfig, ...UICustomizations }); +}; + +const initMicroplanningComponents = () => { + overrideHooks(); + updateCustomConfigs(); + Object.entries(componentsToRegister).forEach(([key, value]) => { + Digit.ComponentRegistryService.setComponent(key, value); + }); +}; + +export { initMicroplanningComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js new file mode 100644 index 00000000000..a358dbbedb1 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js @@ -0,0 +1,61 @@ +import { AutoRenew, Close, FileDownload } from "@egovernments/digit-ui-svg-components"; +import React, { useCallback } from "react"; +import PropTypes from "prop-types"; + +export const ButtonType1 = (props) => { + return ( +
+

{props.text}

+
+ ); +}; + +ButtonType1.propTypes = { + text: PropTypes.string.isRequired, +}; + +export const ButtonType2 = (props) => { + return ( +
+ {props.showDownloadIcon && ( +
+ +
+ )} +

{props.text}

+
+ ); +}; + +ButtonType2.propTypes = { + text: PropTypes.string.isRequired, + showDownloadIcon: PropTypes.bool, +}; + +export const ModalHeading = (props) => { + return ( +

+ {props.label} +

+ ); +}; + +ModalHeading.propTypes = { + label: PropTypes.string.isRequired, + className: PropTypes.string, + style: PropTypes.object, +}; + +export const CloseButton = ({ clickHandler, style = {} }) => { + return ( + + ); +}; + +CloseButton.propTypes = { + clickHandler: PropTypes.func.isRequired, + style: PropTypes.object, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js new file mode 100644 index 00000000000..f2deacbd46d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js @@ -0,0 +1,41 @@ +import React, { useEffect, useState } from "react"; + +const CustomScaleControl = ({ map }) => { + if (!map) return null; + const [scaleText, setScaleText] = useState(""); + // Function to calculate and update the scale text + const updateScale = () => { + // Calculate the scale based on the map's current zoom level + const maxWidthMeters = map.containerPointToLatLng([0, map.getSize().y]).distanceTo(map.containerPointToLatLng([100, map.getSize().y])); + const scale = maxWidthMeters / 1000; // Convert to kilometers + + // Format the scale text + const scaleTextData = scale < 1 ? `${Math.round(scale * 1000)} m` : `${Math.round(Math.round(scale.toFixed(0) / 10) * 10)} km`; + + // Update the scale text in the container element + setScaleText(scaleTextData); + }; + + // Effect to update the scale text when the map component mounts and on map zoom change + useEffect(() => { + // Update the scale text initially + updateScale(); + + // Register the map's zoom events to update the scale text + map.on("zoomend", updateScale); + + // Clean up event listener when the component unmounts + return () => { + map.off("zoomend", updateScale); + }; + }, [map]); + + return ( +
+ {scaleText} + + ); +}; + +export default CustomScaleControl; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js new file mode 100644 index 00000000000..c2cf8bac4fb --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js @@ -0,0 +1,607 @@ +import React, { useState, useEffect, useCallback, Fragment, useRef } from "react"; +import { useTranslation } from "react-i18next"; +import { Trash } from "@egovernments/digit-ui-svg-components"; +import { CloseButton, ModalHeading } from "./CommonComponents"; +import { Dropdown, TextInput, Toast } from "@egovernments/digit-ui-components"; +import { useMyContext } from "../utils/context"; +import { tourSteps } from "../configs/tourSteps"; +import { v4 as uuidv4 } from "uuid"; +import { PlusWithSurroundingCircle } from "../icons/Svg"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; +import { Button, Modal } from "@egovernments/digit-ui-react-components"; +const page = "hypothesis"; + +const Hypothesis = ({ + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + setToast, +}) => { + const { t } = useTranslation(); + + // States + const [editable, setEditable] = useState(true); + const [modal, setModalState] = useState("none"); + const [assumptions, setAssumptions] = useState([]); + const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); + const [itemForDeletion, setItemForDeletion] = useState(); + const [exampleOption, setExampleOption] = useState(""); + // const [toast, setToast] = useState(); + const [autofillHypothesis, setAutofillHypothesis] = useState([]); + const { state, dispatch } = useMyContext(); + const [orignalHypothesisCount, setOrignalHypothesisCount] = useState(0); + + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + const setModal = (modalString) => { + const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); + elements.forEach((element) => { + element.classList.toggle("popup-wrap-rest-unfocus-active"); + }); + setModalState(modalString); + }; + + // UseEffect to extract data on first render + useEffect(() => { + if (pages) { + const previouspage = pages[currentPage?.id - 1]; + if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); + else setEditable(true); + } + if (microplanData?.hypothesis) { + const temp = microplanData?.hypothesis; + setAssumptions(temp); + } + + fetchDataAndUpdateState(); + }, []); + + const fetchDataAndUpdateState = useCallback(() => { + const hypothesisAssumptions = state?.HypothesisAssumptions || []; + const temp = hypothesisAssumptions.find((item) => item.campaignType === campaignType); + if (!temp?.assumptions) return; + + const hypothesisAssumptionsList = Array.isArray(temp.assumptions) ? temp.assumptions : []; + setOrignalHypothesisCount(hypothesisAssumptionsList.length); + setExampleOption(hypothesisAssumptionsList.length !== 0 ? hypothesisAssumptionsList[0] : ""); + + const currentHypothesis = microplanData?.hypothesis || assumptions; + const newAssumptions = setAutofillHypothesisData(hypothesisAssumptionsList, currentHypothesis, setAssumptions); + + const newHypothesislist = filterHypothesisList( + newAssumptions.length !== 0 ? newAssumptions : microplanData.hypothesis, + hypothesisAssumptionsList + ); + setHypothesisAssumptionsList(newHypothesislist); + }, [campaignType, microplanData, state, assumptions, setAssumptions]); + + // UseEffect for checking completeness of data before moveing to next section + useEffect(() => { + if (!assumptions || checkDataCompletion !== "true" || !setCheckDataCompletion) return; + // uncomment to activate data change save check + // if (!microplanData?.hypothesis || !_.isEqual(assumptions, microplanData.hypothesis)) setModal("data-change-check"); + // else + updateData(true); + }, [checkDataCompletion]); + + // UseEffect to store current data + useEffect(() => { + if (!assumptions || !setMicroplanData) return; + setMicroplanData((previous) => ({ ...previous, hypothesis: assumptions })); + }, [assumptions]); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + // if (modal === "upload-guidelines") + setCheckDataCompletion("false"); + setModal("none"); + } + }; + + // check if data has changed or not + const updateData = useCallback( + (check) => { + if (!assumptions || !setMicroplanData) return; + if (check) { + if (assumptions.some((item) => item.active && parseFloat(item.value) === 0)) { + setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") }); + setCheckDataCompletion("false"); + return; + } + let newAssumptions = assumptions.map((item) => { + if (parseFloat(item.value) === 0) { + return { ...item, value: 0.01 }; + } + return item; + }); + setMicroplanData((previous) => ({ ...previous, hypothesis: newAssumptions })); + setAssumptions(newAssumptions); + let checkValid = validateAssumptions(assumptions); + checkValid = checkValid && assumptions.filter((subItem) => subItem?.active).length !== 0; + if (checkValid) setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } else { + let checkValid = microplanData?.hypothesis?.every((item) => Object.values(item).every((data) => data !== "")); + checkValid = checkValid && assumptions.length !== 0; + if (checkValid) setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } + }, + [assumptions, setMicroplanData, microplanData, setCheckDataCompletion] + ); + + const validateAssumptions = useCallback((assumptions) => { + return assumptions.filter((item) => item?.active).every((item) => Object.values(item).every((data) => data !== "")) && assumptions.length !== 0; + }, []); + + const cancelUpdateData = useCallback(() => { + setCheckDataCompletion("false"); + setModal("none"); + }, [setCheckDataCompletion, setModal]); + + const closeModal = useCallback(() => { + setModal("none"); + }, []); + + // Function to Delete an assumption + const deleteAssumptionHandlerCallback = useCallback(() => { + deleteAssumptionHandler(itemForDeletion, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, setToast, t); + closeModal(); + }, [itemForDeletion, deleteAssumptionHandler, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, closeModal, setToast, t]); + + const sectionClass = `jk-header-btn-wrapper hypothesis-section ${editable ? "" : "non-editable-component"} popup-wrap-rest-unfocus `; + + return ( + <> +
+
+ {/* NonInterractable Section */} + + {/* Interractable Section that includes the example as well as the assumptions */} + +
+
+
+ {modal === "delete-conformation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={deleteAssumptionHandlerCallback} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={closeModal} + > +
+

{t("HYPOTHESIS_INSTRUCTIONS_DELETE_ENTRY_CONFIRMATION")}

+
+
+ )} +
+ + ); +}; + +// Function to add a new assumption +const addAssumptionsHandler = (setAssumptions) => { + const uuid = uuidv4(); + setAssumptions((previous) => [ + ...previous, + { + id: uuid, + // previous.length ? previous[previous.length - 1].id + 1 : 0, + key: "", + value: "", + active: true, + }, + ]); +}; + +// Defination for NonInterractable Section +const NonInterractableSection = React.memo(({ t }) => { + return ( +
+

{t("HEADING_HYPOTHESIS")}

+

{t("INSTRUCTION_HYPOTHESIS")}

+
+ ); +}); + +// Defination for NonInterractable Section +const InterractableSection = React.memo( + ({ assumptions, setAssumptions, hypothesisAssumptionsList, setHypothesisAssumptionsList, setModal, setItemForDeletion, exampleOption, t }) => { + const itemRefs = useRef([]); + const [expandedIndex, setExpandedIndex] = useState(null); + const scrollContainerRef = useRef(null); + const [renderCycle, setRenderCycle] = useState(0); + + useEffect(() => { + if (expandedIndex !== null) { + setRenderCycle(0); // Reset render cycle count when expandedIndex changes + } + }, [expandedIndex]); + + useEffect(() => { + // Scroll to the expanded item after the state has updated and the DOM has re-rendered + if (renderCycle < 2) { + setRenderCycle((prev) => prev + 1); // Increment render cycle count + } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { + try { + const parentElement = itemRefs.current[expandedIndex]; + const childElement = itemRefs.current[expandedIndex].children[1]; + + if (parentElement) { + const scrollContainer = scrollContainerRef.current; + const parentRect = parentElement.getBoundingClientRect(); + const containerRect = scrollContainer.getBoundingClientRect(); + + // Calculate the offset from the top of the container + const offset = parentRect.top - containerRect.top; + + // Scroll the container + scrollContainer.scrollTo({ + top: scrollContainer.scrollTop + offset - 10, + behavior: "smooth", + }); + } + + if (childElement) { + childElement.focus(); + } + } catch (error) { + console.error("Error scrolling to element:", error); + } + } + }, [renderCycle, expandedIndex]); + + useEffect(() => { + if (expandedIndex !== null) { + const observer = new MutationObserver(() => { + setRenderCycle((prev) => prev + 1); // Trigger render cycle when the DOM changes + }); + + if (itemRefs.current[expandedIndex]) { + observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); + } + + return () => observer.disconnect(); + } + }, [expandedIndex]); + + const toggleExpand = (index) => { + setExpandedIndex(index === expandedIndex ? null : index); + }; + + // Handler for deleting an assumption on conformation + const deleteHandler = useCallback( + (item) => { + setModal("delete-conformation"); + setItemForDeletion(item); + }, + [setModal, setItemForDeletion] + ); + + return ( +
+ +
+
+
+

{t("KEY")}

+
+
+

{t("VALUE")}

+
+
+ +
+
+ {assumptions + ?.filter((item) => item.active) + ?.map((item, index) => ( +
item.active)?.length - 1 ? "last-container" : "" + } `} + > +
{ + itemRefs.current[index] = el; + }} + onClick={() => { + toggleExpand(index); + }} + > + +
+
+ +
+
+ ))} +
+
+ ); + } +); + +const Example = ({ exampleOption, t }) => { + return ( +
+

{t("EXAMPLE")}

+
+
+

{t("KEY")}

+ +

{t("HYPOTHESIS_KEY_HELP_TEXT")}

+
+
+

{t("VALUE")}

+ +

{t("HYPOTHESIS_VALUE_HELP_TEXT")}

+
+
+
+ ); +}; + +const deleteAssumptionHandler = (item, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, setToast, t) => { + let add = true; + setAssumptions((previous) => { + if (!previous.length) return []; + if (previous.filter((item) => item.active)?.length <= 1) { + setToast({ state: "error", message: t("ERROR_CANNOT_DELETE_LAST_HYPOTHESIS") }); + add = false; + return previous; + } + // const filteredData = previous.filter((data) => data.id !== item.id); + const deletionElementIndex = previous.findIndex((data) => data.id === item.id); + const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data)); + return filteredData || []; + }); + if (add && item && item.key) + setHypothesisAssumptionsList((previous) => { + if (!previous.includes(item.key)) return [...previous, item.key]; + return previous; // Return previous array if key already exists + }); + setItemForDeletion(); +}; + +const Select = React.memo(({ item, assumptions, setAssumptions, disabled = false, options, setOptions, t }) => { + const [selected, setSelected] = useState(); + const [filteredOptions, setFilteredOptions] = useState([]); + + useEffect(() => { + if (item?.key) setSelected({ code: item.key }); + }, [item]); + + useEffect(() => { + if (!options) return; + const filteredOptions = options.length ? options : []; + if (item?.key && !filteredOptions.includes(item.key)) { + setFilteredOptions([item.key, ...filteredOptions]); + } else setFilteredOptions(filteredOptions); + }, [options]); + + const selectChangeHandler = useCallback( + (e) => { + const existingEntry = assumptions.find((item) => item?.active && item?.key === e?.code); + if (existingEntry) return; + const newDataSegment = { + ...item, + id: item.id, + key: e?.code, + value: item.value, + }; + setAssumptions((previous) => { + const filteredAssumptionsList = previous.map((data) => { + if (data.id === item.id) return newDataSegment; + return data; + }); + return filteredAssumptionsList; + }); + + setOptions((previous) => { + let newOptions = previous.filter((item) => item !== e?.code); + if (selected && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code); + return newOptions; + }); + }, + [assumptions, item, selected, setAssumptions, setOptions] + ); + + return ( + ({ code: item }))} + selected={selected} + optionKey="code" + select={selectChangeHandler} + // style={{ width: "100%", backgroundColor: "rgb(0,0,0,0)", position:"sticky" }} + optionCardStyles={{ position: "absolute" }} + placeholder={t("SELECT_OPTION")} + showToolTip={true} + /> + ); +}); + +const Input = React.memo(({ item, setAssumptions, t, disabled = false }) => { + const [inputValue, setInputValue] = useState(""); + + useEffect(() => { + if (item) setInputValue(item.value); + }, [item]); + + const inputChangeHandler = useCallback( + (e) => { + if (e.target.value.includes("+") || e.target.value.includes("e")) return; + if ((e.target.value < 0 || e.target.value > 10000000000) && e.target.value !== "") return; + let value; + const decimalIndex = e.target.value.indexOf("."); + if (decimalIndex !== -1) { + const numDecimals = e.target.value.length - decimalIndex - 1; + value = e.target.value; + if (numDecimals <= 2) { + value = e.target.value; + } else if (numDecimals > 2) { + value = value.substring(0, decimalIndex + 3); + } + } else value = Number.parseFloat(e.target.value); + + setInputValue(!Number.isNaN(value) ? value : ""); + const newDataSegment = { + ...item, + id: item.id, + key: item.key, + value: !Number.isNaN(value) ? value : "", + }; + setAssumptions((previous) => { + const filteredAssumptionsList = previous.map((data) => { + if (data.id === item.id) { + return newDataSegment; + } + return data; + }); + return filteredAssumptionsList; + }); + }, + [item, setAssumptions] + ); + + return ( + + ); +}); + +const setAutofillHypothesisData = (autofillHypothesis, assumptions, setAssumptions) => { + if (assumptions?.length !== 0) return []; + let newAssumptions = []; + for (let i in autofillHypothesis) { + const uuid = uuidv4(); + newAssumptions.push({ + id: uuid, + key: autofillHypothesis[Number(i)], + value: "", + active: true, + }); + } + setAssumptions(newAssumptions); + return newAssumptions; +}; + +const filterHypothesisList = (assumptions, hypothesisList) => { + let alreadySelectedHypothesis = assumptions.filter((item) => item?.active).map((item) => item?.key) || []; + return hypothesisList.filter((item) => !alreadySelectedHypothesis.includes(item)); +}; + +export default Hypothesis; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js new file mode 100644 index 00000000000..23bbef8ae29 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js @@ -0,0 +1,113 @@ +import { Button, DownloadIcon, SVG } from "@egovernments/digit-ui-react-components"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +export const JsonPreviewInExcelForm = (props) => { + const { t } = useTranslation(); + const sheetsData = props?.sheetsData; + const [currentSheetName, setCurrentSheetName] = useState(Object.keys(sheetsData).length > 0 ? Object.keys(sheetsData)[0] : undefined); + return ( +
+
+
+
+ {props?.errorLocationObject?.[currentSheetName] &&

{t("USER_DIRECTIONS_FOR_ERROR_MESSAGE")}

} + {/* {Object.entries(sheetsData).map(([sheetName, sheetData], index) => ( */} +
+ + + + {sheetsData?.[currentSheetName]?.[0] + ?.filter((header) => header) + .map((header) => ( + + ))} + + + + {sheetsData?.[currentSheetName]?.slice(1).map((rowData, rowIndex) => ( + + {Object.values(sheetsData?.[currentSheetName]?.[0])?.map((_, cellIndex) => { + const headerName = sheetsData?.[currentSheetName]?.[0]?.[cellIndex]; + const error = headerName ? props?.errorLocationObject?.[currentSheetName]?.[rowIndex]?.[headerName] : undefined; + let convertedError; + if (typeof error?.[0] === "object") { + let { error: actualError, ...otherProperties } = error[0]; + convertedError = t(actualError, otherProperties?.values); + } else { + convertedError = t(error); + } + const rowHasError = + typeof props?.errorLocationObject?.[currentSheetName]?.[rowIndex] === "object" + ? Object.keys(props?.errorLocationObject?.[currentSheetName]?.[rowIndex]).length !== 0 + : undefined; + return ( + + ); + })} + + ))} + +
{t(header)}
+ {cellIndex === 0 && rowHasError &&
} + + {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : ""} +
+
+
+ {Object.entries(sheetsData).map(([sheetName, sheetData], index) => ( + + ))} +
+ {/* ))} */} +
+
+ ); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js new file mode 100644 index 00000000000..75f953c8804 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js @@ -0,0 +1,445 @@ +// Importing necessary modules +import { Card, Header } from "@egovernments/digit-ui-components"; +import L from "leaflet"; +import "leaflet/dist/leaflet.css"; +import React, { useCallback, useEffect, useRef, useState, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import ZoomControl from "./ZoomControl"; +import CustomScaleControl from "./CustomScaleControl"; +import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; +import { LoaderWithGap } from "@egovernments/digit-ui-react-components"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { + MapFilterIndex, + MapChoroplethIndex, + ChoroplethSelection, + FilterSection, + BoundarySelection, + BaseMapSwitcher, +} from "./MappingHelperComponents"; +import { + enableMapInteractions, + disableMapInteractions, + removeAllLayers, + filterBoundarySelection, + findBounds, + addGeojsonToMap, + addFilterProperties, + addChoroplethProperties, + prepareGeojson, + extractGeoData, +} from "../utils/mappingUtils"; + +const page = "mapping"; + +// Mapping component definition +const Mapping = ({ + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + setToast, + ...props +}) => { + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + + // request body for boundary hierarchy api + var reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + // hierarchyType: "Microplan", + hierarchyType: campaignData?.hierarchyType, + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return ( + data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ + ...item, + parentBoundaryType: item?.parentBoundaryType + ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` + : null, + boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, + })) || {} + ); + }, + }, + }; + const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); + // request body for boundary hierarchy api + var reqCriteria = { + url: `/boundary-service/boundary/_search`, + params: { codes: Digit.ULBService.getCurrentTenantId(), tenantId: Digit.ULBService.getCurrentTenantId() }, + body: {}, + config: { + select: (data) => { + return data?.Boundary || {}; + }, + }, + }; + const { isLoading: isBoundaryLoading, data: Boundary } = Digit.Hooks.useCustomAPIHook(reqCriteria); + + // Setting up state variables + const [editable, setEditable] = useState(true); + const { t } = useTranslation(); + var [map, setMap] = useState(null); + var [_mapNode, set__mapNode] = useState("map"); + const [layers, setLayer] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [filterDataOrigin, setFilterDataOrigin] = useState({}); + const [dataAvailability, setDataAvailability] = useState("true"); + // const [toast, setToast] = useState(); + const [baseMaps, setBaseMaps] = useState({}); + const [selectedBaseMap, setSelectedBaseMap] = useState({}); + const [selectedBaseMapName, setSelectedBaseMapName] = useState(""); + const [showBaseMapSelector, setShowBaseMapSelector] = useState(false); + const [boundaryData, setBoundaryData] = useState({}); // State for boundary data + const [filterData, setFilterData] = useState({}); // State for facility data + const [boundarySelections, setBoundarySelections] = useState({}); + const [isboundarySelectionSelected, setIsboundarySelectionSelected] = useState(false); + const { state, dispatch } = useMyContext(); + const [filterPropertyNames, setFilterPropertyNames] = useState(); + const [filterProperties, setFilterProperties] = useState(); + const [showFilterOptions, setShowFilterOptions] = useState(false); + const [filterSelections, setFilterSelections] = useState([]); + const [choroplethProperties, setChoroplethProperties] = useState([]); + const [showChoroplethOptions, setShowChoroplethOptions] = useState(false); + const [choroplethProperty, setChoroplethProperty] = useState(); + const [dataCompleteness, setDataCompleteness] = useState(); + const basemapRef = useRef(); + const filterBoundaryRef = useRef(); + const showChoroplethOptionRef = useRef(); + const showFilterOptionRef = useRef(); + const [loader, setLoader] = useState(false); + + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + // Effect to initialize map when data is fetched + useEffect(() => { + if (!state || !Boundary) return; + const UIConfiguration = state?.UIConfiguration; + if (UIConfiguration) { + const filterDataOriginList = UIConfiguration.find((item) => item.name === "mapping"); + setFilterDataOrigin(filterDataOriginList); + } + const BaseMapLayers = state?.BaseMapLayers; + const schemas = state?.Schemas; + if (schemas) setValidationSchemas(schemas); + if (!BaseMapLayers || (BaseMapLayers && BaseMapLayers.length === 0)) return; + let baseMaps = {}; + let defaultBaseMap = undefined; + BaseMapLayers.forEach((item) => { + if (item.url) { + const layer = L.tileLayer(item.url, { + minZoom: item?.minZoom, + maxZoom: item?.maxZoom, + attribution: item?.attribution, + }); + baseMaps[item?.name] = { + metadata: item, + layer, + }; + if (!defaultBaseMap) + defaultBaseMap = { + name: item?.name, + layer, + }; + } + }); + setSelectedBaseMapName(defaultBaseMap?.name); + setBaseMaps(baseMaps); + if (!map) { + init(_mapNode, defaultBaseMap, Boundary); + } + }, [Boundary]); + + useEffect(() => { + if (map && filterDataOrigin && Object.keys(filterDataOrigin).length !== 0) { + setLoader("LOADING"); + // Check if all the data is present or not, if it is then extract it in a format that can be used for mapping and other mapping related operations + extractGeoData( + campaignType, + microplanData, + filterDataOrigin, + validationSchemas, + setToast, + setDataAvailability, + hierarchy, + setBoundaryData, + setFilterData, + setFilterProperties, + setFilterSelections, + setFilterPropertyNames, + state, + setChoroplethProperties, + setDataCompleteness, + t + ); + setLoader(false); + } + }, [filterDataOrigin, hierarchy]); + + // Function to initialize map + const init = (id, defaultBaseMap, Boundary) => { + if (map !== null) return; + + // let bounds = findBounds(Boundary); + + let mapConfig = { + center: [0, 0], + zoomControl: false, + zoom: 3, + scrollwheel: true, + minZoom: 3, + }; + + let map_i = L.map(id, mapConfig); + var verticalBounds = L.latLngBounds(L.latLng(-90, -170), L.latLng(85, 190)); + map_i.on("drag", () => { + map_i.panInsideBounds(verticalBounds, { animate: true }); + }); + map_i.on("zoom", () => { + map_i.panInsideBounds(verticalBounds, { animate: true }); + }); + const defaultBaseLayer = defaultBaseMap?.layer.addTo(map_i); + // if (bounds) map_i.fitBounds(bounds); + setSelectedBaseMap(defaultBaseLayer); + setMap(map_i); + }; + + const handleBaseMapToggle = (newBaseMap) => { + if (map) { + const currentBaseLayer = selectedBaseMap; + if (currentBaseLayer) { + currentBaseLayer.remove(); + } + const newBaseLayer = baseMaps[newBaseMap].layer.addTo(map); + // Add the new base layer to the bottom of the layer stack + newBaseLayer.addTo(map); + + // Update the baseLayer state + setSelectedBaseMap(newBaseLayer); + setSelectedBaseMapName(newBaseMap); + } + }; + + // showing selected boundary data + useEffect(() => { + if (!boundarySelections && !choroplethProperty && !filterSelections) return; + setLoader("LOADING"); + try { + removeAllLayers(map, layers); + const { filteredSelection, childrenList } = filterBoundarySelection(boundaryData, boundarySelections); + let newLayer = []; + let addOn = { + fillColor: "rgba(255, 107, 43, 0)", + weight: 3.5, + opacity: 1, + color: "rgba(176, 176, 176, 1)", + fillOpacity: 0, + fill: "rgb(4,136,219,1)", + child: !childrenList || childrenList.length === 0, // so that this layer also has mounse in and mouse out events + }; + let geojsonsBase = prepareGeojson(boundaryData, "ALL", addOn); + if (geojsonsBase) { + let baseLayer = addGeojsonToMap(map, geojsonsBase, t); + if (baseLayer) newLayer.push(baseLayer); + let bounds = findBounds(geojsonsBase); + if (bounds) map.fitBounds(bounds); + } + + addOn = { + fillColor: "rgba(255, 107, 43, 1)", + weight: 2.5, + opacity: 1, + color: "rgba(255, 255, 255, 1)", + fillOpacity: 0.22, + fill: "rgb(4,136,219)", + }; + + let geojsonLayer; + if (choroplethProperty) { + if (dataCompleteness === "partial" || dataCompleteness === "false" || dataCompleteness === undefined) { + setToast({ + state: "warning", + message: t("DISPLAYING_DATA_ONLY_FOR_UPLOADED_BOUNDARIES"), + }); + } + + let choroplethGeojson = prepareGeojson(boundaryData, "ALL", { ...addOn, child: true, fillColor: "rgb(0,0,0,0)" }) || []; + if (choroplethGeojson && choroplethGeojson.length !== 0) + choroplethGeojson = addChoroplethProperties(choroplethGeojson, choroplethProperty, filteredSelection); + geojsonLayer = addGeojsonToMap(map, choroplethGeojson, t); + if (geojsonLayer) { + newLayer.push(geojsonLayer); + } + } + geojsonLayer = null; + const geojsons = prepareGeojson(boundaryData, filteredSelection, addOn); + if (geojsons && geojsons.length > 0) { + geojsonLayer = addGeojsonToMap(map, geojsons, t); + newLayer.push(geojsonLayer); + let bounds = findBounds(geojsons); + if (bounds) map.fitBounds(bounds); + } + + const childrenGeojson = prepareGeojson(boundaryData, childrenList, { ...addOn, opacity: 0, fillOpacity: 0, child: true }); + let childrenGeojsonLayer = addGeojsonToMap(map, childrenGeojson, t); + if (childrenGeojsonLayer) newLayer.push(childrenGeojsonLayer); + + //filters + const filterGeojsons = prepareGeojson(filterData, filteredSelection && filteredSelection.length !== 0 ? filteredSelection : "ALL", addOn); + const filterGeojsonWithProperties = addFilterProperties(filterGeojsons, filterSelections, filterPropertyNames, state?.MapFilters); + let filterGeojsonLayer = addGeojsonToMap(map, filterGeojsonWithProperties, t); + if (filterGeojsonLayer) newLayer.push(filterGeojsonLayer); + + setLayer(newLayer); + } catch (error) { + console.error("Error while adding geojson to map: ", error.message); + } + setLoader(false); + }, [boundarySelections, choroplethProperty, filterSelections]); + + const handleOutsideClickAndSubmitSimultaneously = useCallback(() => { + if (isboundarySelectionSelected) setIsboundarySelectionSelected(false); + if (showBaseMapSelector) setShowBaseMapSelector(false); + if (showFilterOptions) setShowFilterOptions(false); + if (showChoroplethOptions) setShowChoroplethOptions(false); + }, [ + isboundarySelectionSelected, + showBaseMapSelector, + showFilterOptions, + showChoroplethOptions, + setIsboundarySelectionSelected, + setShowBaseMapSelector, + setShowFilterOptions, + setShowChoroplethOptions, + ]); + Digit?.Hooks.useClickOutside(filterBoundaryRef, handleOutsideClickAndSubmitSimultaneously, isboundarySelectionSelected, { capture: true }); + Digit?.Hooks.useClickOutside(basemapRef, handleOutsideClickAndSubmitSimultaneously, showBaseMapSelector, { capture: true }); + Digit?.Hooks.useClickOutside(showFilterOptionRef, handleOutsideClickAndSubmitSimultaneously, showFilterOptions, { capture: true }); + Digit?.Hooks.useClickOutside(showChoroplethOptionRef, handleOutsideClickAndSubmitSimultaneously, showChoroplethOptions, { capture: true }); + + // function to stop mouse event propogation from custom comopents to leaflet map + const handleMouseDownAndScroll = (event) => { + event?.stopPropagation(); + disableMapInteractions(map); + }; + + const handleMouseUpAndScroll = (event) => { + enableMapInteractions(map); + }; + useEffect(() => { + if (isboundarySelectionSelected || showBaseMapSelector || showFilterOptions || showChoroplethOptions) handleMouseDownAndScroll(); + else handleMouseUpAndScroll(); + }, [isboundarySelectionSelected, showBaseMapSelector, showFilterOptions, showChoroplethOptions, choroplethProperty, filterPropertyNames]); + + // Rendering component + return ( +
+
{t("MAPPING")}
+ + + {/* Container for map */} + +
+
+
+ +
+ {filterProperties && Object.keys(filterProperties).length !== 0 && ( + + )} + +
+ +
+ +
+ {DigitSvgs.NorthArrow && } +
+ +
+ +
+ {filterSelections && filterSelections.length > 0 && ( + + )} + {choroplethProperty && } +
+
+
+
+ {loader && } +
+ ); +}; + +// Exporting Mapping component +export default Mapping; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js new file mode 100644 index 00000000000..9cea19a943f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js @@ -0,0 +1,513 @@ +// Importing necessary modules +import { Card, CardLabel, MultiSelectDropdown, Button, CheckBox, RadioButtons } from "@egovernments/digit-ui-components"; +import "leaflet/dist/leaflet.css"; +import React, { memo, useCallback, useEffect, useMemo, useRef, useState, Fragment } from "react"; +import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; +import { CardSectionHeader, InfoIconOutline, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import { fetchDropdownValues } from "../utils/processHierarchyAndData"; +import { MapChoroplethGradientColors, PRIMARY_THEME_COLOR } from "../configs/constants"; +import { ModalHeading } from "./CommonComponents"; +import * as MicroplanIconCollection from "../icons/Svg"; +import { generatePreviewUrl } from "../utils/mappingUtils"; + +const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs }; + +export function checkTruthyKeys(obj) { + for (let key in obj) { + if (Object.hasOwn(obj, key)) { + if (obj[key] && !(Array.isArray(obj[key]) && obj[key].length === 0)) { + return true; + } + } + } + return false; +} + +export const MapFilterIndex = ({ filterSelections, MapFilters, t }) => { + return ( +
+ {filterSelections && filterSelections.length > 0 ? ( + <> + {filterSelections.map((item, index) => ( + //
+ + //

{t(item)}

+ //
+ ))} + + ) : ( + "" + )} +
+ ); +}; + +// Function to create the gradient from the colors array for choropleth index +export const MapChoroplethIndex = ({ t, choroplethProperty }) => { + const createGradientString = (colors) => { + return colors.map((color) => `${color.color} ${color.percent}%`).join(", "); + }; + + const gradientString = createGradientString(MapChoroplethGradientColors); + const gradientStyle = { + background: `linear-gradient(to right, ${gradientString})`, + }; + + return ( +
+
+

0%

+
+

100%

+
+

{t(choroplethProperty)}

+
+ ); +}; + +export const FilterItemBuilder = ({ item, MapFilters, t }) => { + let temp = MapFilters?.find((e) => e?.name === item)?.icon?.index; + let DynamicIcon = IconCollection?.[temp]; + // let icon; + // if (typeof DynamicIcon === "function") icon = DynamicIcon({}); + return DynamicIcon && typeof DynamicIcon === "function" ? ( +
+ +

{t(item)}

+
+ ) : ( + //
+ "" + ); +}; + +export const ChoroplethSelection = memo( + ({ + choroplethProperties, + showChoroplethOptions, + showChoroplethOptionRef, + setShowChoroplethOptions, + choroplethProperty, + setChoroplethProperty, + t, + }) => { + const handleChange = useCallback( + (value) => { + setChoroplethProperty(value?.code); + }, + [choroplethProperties] + ); + + return ( +
+
setShowChoroplethOptions((previous) => !previous)} + onKeyUp={() => setShowChoroplethOptions((previous) => !previous)} + tabIndex={0} + > +

{t("VISUALIZATIONS")}

+
+ {DigitSvgs.FilterAlt && } +
+
+ {showChoroplethOptions && ( +
+
+ ({ name: item, id: item, code: item }))} + optionsKey="name" + onSelect={handleChange} + selectedOption={choroplethProperty} + /> +
+
+ )} +
+ ); + } +); + +export const FilterSection = memo( + ({ filterProperties, showFilterOptionRef, showFilterOptions, setShowFilterOptions, filterSelections, setFilterSelections, t }) => { + const handleChange = useCallback( + (e, item) => { + let tempFilterSelections = [...filterSelections]; // Clone the array to avoid mutating state directly + if (filterSelections.includes(item)) { + tempFilterSelections = tempFilterSelections.filter((element) => element !== item); + } else { + tempFilterSelections.push(item); + } + setFilterSelections(tempFilterSelections); + }, + [filterSelections] + ); + + return ( +
+
setShowFilterOptions((previous) => !previous)} + onKeyUp={() => setShowFilterOptions((previous) => !previous)} + tabIndex={0} + > +

{t("FILTERS")}

+
+ {DigitSvgs.FilterAlt && } +
+
+ {showFilterOptions && ( +
+
+ {filterProperties.map((item) => ( +
+ handleChange(e, item)} + label={t(item)} + checked={!!filterSelections.includes(item)} + mainClassName="mainClassName" + labelClassName="labelClassName" + inputWrapperClassName="inputWrapperClassName" + inputClassName="inputClassName" + inputIconClassname="inputIconClassname" + iconFill={PRIMARY_THEME_COLOR} + onLabelClick={(e) => handleChange(e, item)} + /> +
+ ))} +
+
+ )} +
+ ); + } +); + +export const BoundarySelection = memo( + ({ + boundarySelections, + setBoundarySelections, + boundaryData, + hierarchy, + filterBoundaryRef, + isboundarySelectionSelected, + setIsboundarySelectionSelected, + t, + }) => { + const [processedHierarchy, setProcessedHierarchy] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [showConfirmationModal, setShowConformationModal] = useState(false); + const itemRefs = useRef([]); + const [expandedIndex, setExpandedIndex] = useState(null); + const scrollContainerRef = useRef(null); + const [changedBoundaryType, setChangedBoundaryType] = useState(""); + const [isScrollable, setIsScrollable] = useState(false); + + useEffect(() => { + // Scroll to the expanded item's child element after the state has updated and the DOM has re-rendered + if (expandedIndex !== null && itemRefs.current[expandedIndex]) { + // Use a timeout to ensure the DOM has updated + setTimeout(() => { + const childElement = itemRefs.current[expandedIndex].children[0]; // Assuming child content is the second child + // if (childElement) { + // childElement.scrollIntoView({ behavior: 'smooth' }); + // } + if (childElement) { + const scrollContainer = scrollContainerRef.current; + const childElementBound = childElement.getBoundingClientRect(); + const containerRect = scrollContainer.getBoundingClientRect(); + + // Calculate the offset from the top of the container + const offset = childElementBound.top - containerRect.top; + + // Scroll the container + scrollContainer.scrollTo({ + top: scrollContainer.scrollTop + offset - 10, + behavior: "smooth", + }); + } + }, 0); + } + }, [expandedIndex]); + + const toggleExpand = (index) => { + setExpandedIndex(index === expandedIndex ? null : index); + }; + + // Filtering out dropdown values + useEffect(() => { + if (!boundaryData || !hierarchy) return; + const processedHierarchyTemp = fetchDropdownValues( + boundaryData, + processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, + boundarySelections, + changedBoundaryType + ); + setProcessedHierarchy(processedHierarchyTemp); + setIsLoading(false); + }, [boundaryData, hierarchy, boundarySelections]); + + const handleClearAll = () => { + setShowConformationModal(true); + }; + + const handleSubmitConfModal = () => { + setBoundarySelections({}); + setShowConformationModal(false); + }; + + const handleCancelConfModal = () => { + setShowConformationModal(false); + }; + + const checkScrollbar = () => { + if (scrollContainerRef.current) { + setIsScrollable(scrollContainerRef.current.scrollHeight > scrollContainerRef.current.clientHeight); + } + }; + + useEffect(() => { + // Initial check + checkScrollbar(); + + // Check on resize + window.addEventListener("resize", checkScrollbar); + + // Cleanup event listeners on component unmount + return () => { + window.removeEventListener("resize", checkScrollbar); + }; + }, [isboundarySelectionSelected]); + + useEffect(() => { + const content = scrollContainerRef.current; + content.addEventListener("scroll", checkScrollbar); + + return () => { + content.removeEventListener("scroll", checkScrollbar); + }; + }, [scrollContainerRef]); + + return ( +
+ {isLoading && } +
+ ); + } +); + +export const BaseMapSwitcher = ({ + baseMaps, + showBaseMapSelector, + setShowBaseMapSelector, + handleBaseMapToggle, + selectedBaseMapName, + basemapRef, + t, +}) => { + if (!baseMaps) return null; + return ( +
+
setShowBaseMapSelector((previous) => !previous)} + onKeyUp={() => setShowBaseMapSelector((previous) => !previous)} + tabIndex={0} + > +

{t("LAYERS")}

+
{DigitSvgs.Layers && }
+
+
+ {showBaseMapSelector && ( +
+ {Object.entries(baseMaps).map(([name, baseMap], index) => { + return ( +
+ {t("ERROR_LOADING_BASE_MAP")} handleBaseMapToggle(name)} + /> +

{t(name)}

+
+ ); + })} +
+ )} +
+
+ ); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js new file mode 100644 index 00000000000..b6a2fb9a205 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js @@ -0,0 +1,111 @@ +import React, { memo } from "react"; +import { ActionBar, ArrowForward, Banner } from "@egovernments/digit-ui-components"; +import { useTranslation } from "react-i18next"; +import { ArrowBack, FileDownload } from "@egovernments/digit-ui-svg-components"; +import { convertJsonToXlsx, writeWorkbookToBuffer } from "../utils/jsonToExcelBlob"; +import { Button } from "@egovernments/digit-ui-react-components"; +import { useHistory } from "react-router-dom"; +import { Link } from "react-router-dom/cjs/react-router-dom.min"; +import { PRIMARY_THEME_COLOR, commonColumn } from "../configs/constants"; +import { colorHeaders } from "../utils/uploadUtils"; + +const MicroplanCreatedScreen = memo(({ microplanData, ...props }) => { + const { t } = useTranslation(); + const history = useHistory(); + + const downloadMicroplan = async () => { + try { + if (!microplanData?.microplanPreview) return; + const data = _.cloneDeep(microplanData?.microplanPreview?.previewData); + const commonColumnIndex = data[0]?.findIndex((item) => item === commonColumn); + data[0] = data[0].map((item) => t(item)); + + for (const i in data) { + data[i] = data[i].map((item, index) => + item ? (typeof item === "number" ? item : index === commonColumnIndex ? item : t(item)) : t("NO_DATA") + ); + } + + const headers = data?.[0] || []; + const workbook = await convertJsonToXlsx({ [microplanData?.microplanDetails?.name]: data }, {}, true); + colorHeaders(workbook, headers, [], []); + const blob = await writeWorkbookToBuffer(workbook); + + if (!blob) { + return; + } + + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + + const fileNameParts = microplanData?.microplanDetails?.name; + if (!fileNameParts) { + return; + } + + link.download = fileNameParts; + link.click(); + URL.revokeObjectURL(url); + } catch (error) { + console.error(`Failed to download microplan: ${error.message}`, error); + } + }; + + const clickGoHome = () => { + history.push("/microplan-ui/employee"); + }; + + return ( +
+
+
+ +
+

{t("MICROPLAN_GENERATED_SUCCESSFULLY_DESCRIPTIION")}

+
+
+
+ + + {/* Back button */} +
+ ); +}); + +export default MicroplanCreatedScreen; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js new file mode 100644 index 00000000000..fbc73bd6569 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js @@ -0,0 +1,294 @@ +import React, { Fragment, useState, useEffect, useCallback } from "react"; +import { + Card, + CardSubHeader, + CardSectionHeader, + StatusTable, + Row, + Loader, + LabelFieldPair, + CardLabel, + TextInput, + LoaderWithGap, +} from "@egovernments/digit-ui-react-components"; +import { useTranslation } from "react-i18next"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { InfoCard, Modal, Toast } from "@egovernments/digit-ui-components"; +import { CloseButton, ModalHeading } from "./CommonComponents"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; +import SearchPlanConfig from "../services/SearchPlanConfig"; + +const page = "microplanDetails"; + +const MicroplanDetails = ({ + MicroplanName = "default", + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + setToast, + ...props +}) => { + const { t } = useTranslation(); + const [microplan, setMicroplan] = useState(Digit.SessionStorage.get("microplanData")?.microplanDetails?.name); + const { state, dispatch } = useMyContext(); + const [modal, setModal] = useState("none"); + // const [toast, setToast] = useState(); + const [showNamingConventions, setShowNamingConventions] = useState(false); + const [loader, setLoader] = useState(false); + + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + select: (data) => { + const campaignCard = [ + { + label: t("CAMPAIGN_NAME"), + value: data?.campaignName ? data?.campaignName : t("ES_COMMON_NA"), + }, + { + label: t(`CAMPAIGN_TYPE`), + value: data?.projectType ? t(`CAMPAIGN_TYPE_${data?.projectType}`) : t("ES_COMMON_NA"), + }, + { + label: t(`CAMPAIGN_BENEFICIARY_TYPE`), + value: data?.additionalDetails?.beneficiaryType + ? t(`CAMPAIGN_BENEFICIARY_TYPE${data?.additionalDetails?.beneficiaryType}`) + : t("ES_COMMON_NA"), + }, + { + label: t("CAMPAIGN_DATE"), + value: data.startDate + ? data.endDate + ? `${Digit.DateUtils.ConvertEpochToDate(data.startDate)} - ${Digit.DateUtils.ConvertEpochToDate(data.endDate)}` + : Digit.DateUtils.ConvertEpochToDate(data.startDate) + : t("ES_COMMON_NA"), + }, + ]; + return campaignCard; + }, + } + ); + + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + // Save data to ssn of data change + useEffect(() => { + setMicroplanData((previous) => ({ + ...previous, + microplanDetails: { + name: microplan, + }, + })); + }, [microplan]); + + useEffect(() => { + if (checkDataCompletion !== "true" || !setCheckDataCompletion) return; + + updateData(true); + }, [checkDataCompletion]); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + // if (modal === "upload-guidelines") + setCheckDataCompletion("false"); + setModal("none"); + } + }; + const validateMicroplanName = async () => { + try { + setLoader("LOADING"); + const body = { + PlanConfigurationSearchCriteria: { + name: microplan, + tenantId: Digit.ULBService.getCurrentTenantId(), + }, + }; + const response = await SearchPlanConfig(body); + if (response?.PlanConfiguration?.length === 0) { + return true; + } + if (response?.PlanConfiguration?.length === 1) { + if (response?.PlanConfiguration[0].id === microplanData?.planConfigurationId) { + setLoader(); + return true; + } + } + setLoader(); + return false; + } catch (error) { + console.error("Error while checking microplan name duplication: ", error.message); + setLoader(); + return false; + } + }; + // check if data has changed or not + const updateData = useCallback( + async (check) => { + if (checkDataCompletion !== "true" || !setCheckDataCompletion) return; + if (!microplan || !validateName(microplan)) { + setCheckDataCompletion("false"); + setShowNamingConventions(true); + return setToast({ state: "error", message: t("ERROR_MICROPLAN_NAME_CRITERIA") }); + } + const valid = await validateMicroplanName(); + if (!valid) { + setToast({ state: "error", message: t("ERROR_DUPLICATE_MICROPLAN_NAME") }); + setCheckDataCompletion("false"); + return; + } + if (check) { + setMicroplanData((previous) => ({ + ...previous, + microplanDetails: { + name: microplan, + }, + })); + if (!["", null, undefined].includes(microplan)) { + setCheckDataCompletion("valid"); + } else { + setCheckDataCompletion("invalid"); + } + } else { + if (!["", null, undefined].includes(microplanData?.microplanDetails?.name)) { + setCheckDataCompletion("valid"); + } else { + setCheckDataCompletion("invalid"); + } + } + }, + [checkDataCompletion, microplan, microplanData, setCheckDataCompletion, setMicroplanData, validateMicroplanName] + ); + + // const cancelUpdateData = useCallback(() => { + // setCheckDataCompletion(false); + // setModal('none'); + // }, [setCheckDataCompletion, setModal]); + function validateName(name) { + const microplanNamingRegxString = state?.UIConfiguration?.find((item) => item.name === "microplanNamingRegx")?.microplanNamingRegx; + const namePattern = new RegExp(microplanNamingRegxString); + return namePattern.test(name); + } + const onChangeMicroplanName = (e) => { + setMicroplan(e.target.value); + }; + + if (isCampaignLoading) { + return ; + } + + return ( + <> + {loader && } + + + {t("CAMPAIGN_DETAILS")} + + + + {campaignData?.length > 0 && + campaignData?.map((row, idx) => { + return ( + + ); + })} + + + + {t("NAME_YOUR_MP")} +

{t("MP_FOOTER")}

+ + + {`${t("NAME_OF_MP")} `}

*

+
+
+ +
+
+
+ + {state?.UIConfiguration?.find((item) => item.name === "microplanNamingConvention")?.microplanNamingConvention?.map((item, index) => ( +
+

+ {t(index + 1)}. +

+

+ {t(item)} +

+
+ ))} +
, + ]} + /> + + ); +}; + +export default MicroplanDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js new file mode 100644 index 00000000000..1be6619e7a7 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js @@ -0,0 +1,478 @@ +import { Header, Loader } from "@egovernments/digit-ui-components"; +import React, { useCallback, useEffect, useMemo, useState, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { processHierarchyAndData } from "../utils/processHierarchyAndData"; +import { ModalHeading } from "./CommonComponents"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; +import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { + fetchMicroplanPreviewData, + filterObjects, + updateHyothesisAPICall, + filterMicroplanDataToShowWithHierarchySelection, +} from "../utils/microplanPreviewUtils"; +import { + HypothesisValues, + BoundarySelection, + DataPreview, + AppplyChangedHypothesisConfirmation, + Aggregates, +} from "./MicroplanPreviewHelperCompoenents"; + +const page = "microplanPreview"; + +const MicroplanPreview = ({ + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + navigationEvent, + setToast, + ...props +}) => { + const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig(); + const userInfo = Digit.SessionStorage.get("User")?.info; + const { id: campaignId = "" } = Digit.Hooks.useQueryParams(); + const { t } = useTranslation(); + const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); + const [data, setData] = useState([]); + const [dataToShow, setDataToShow] = useState([]); + const [joinByColumns, setJoinByColumns] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [resources, setResources] = useState([]); + const [formulaConfiguration, setFormulaConfiguration] = useState([]); + const [boundarySelections, setBoundarySelections] = useState({}); // state for hierarchy from the data available from uploaded data + const [boundaryData, setBoundaryData] = useState({}); // State for boundary data + // const [toast, setToast] = useState(); + const [modal, setModal] = useState("none"); + const [operatorsObject, setOperatorsObject] = useState([]); + + const [loaderActivation, setLoaderActivation] = useState(false); + + const [userEditedResources, setUserEditedResources] = useState({}); // state to maintain a record of the resources that the user has edited ( boundaryCode : {resource : value}) + const [microplanPreviewAggregates, setMicroplaPreviewAggregates] = useState(); + const { state, dispatch } = useMyContext(); + const [updateHypothesis, setUpdateHypothesis] = useState(false); + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + + // request body for boundary hierarchy api + const reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + hierarchyType: campaignData?.hierarchyType, + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return ( + data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ + ...item, + parentBoundaryType: item?.parentBoundaryType + ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` + : null, + boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, + })) || {} + ); + }, + }, + }; + const { isLoading: ishierarchyLoading, data: hierarchyRawData } = Digit.Hooks.useCustomAPIHook(reqCriteria); + const hierarchy = useMemo(() => { + return hierarchyRawData?.map((item) => item?.boundaryType); + }, [hierarchyRawData]); + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + // UseEffect to extract data on first render + useEffect(() => { + if (microplanData && (microplanData?.ruleEngine || microplanData?.hypothesis)) { + const hypothesisAssumptions = microplanData?.hypothesis || []; + const formulaConfiguration = microplanData?.ruleEngine?.filter((item) => Object.values(item).every((key) => key !== "")) || []; + if (hypothesisAssumptions.length !== 0 && hypothesisAssumptionsList.length === 0) { + setHypothesisAssumptionsList(hypothesisAssumptions); + } + if (formulaConfiguration.length !== 0) { + setFormulaConfiguration(formulaConfiguration); + } + } + if (microplanData?.microplanPreview?.userEditedResources) { + setUserEditedResources(microplanData?.microplanPreview?.userEditedResources); + } + }, []); + + // Fetch and assign MDMS data + useEffect(() => { + if (!state) return; + const UIConfiguration = state?.UIConfiguration; + const schemas = state?.Schemas; + let resourcelist = state?.Resources; + let microplanPreviewAggregatesList = state?.MicroplanPreviewAggregates; + microplanPreviewAggregatesList = microplanPreviewAggregatesList.find((item) => item.campaignType === campaignType)?.data; + if (schemas) setValidationSchemas(schemas); + resourcelist = resourcelist.find((item) => item.campaignType === campaignType)?.data; + if (resourcelist) setResources(resourcelist); + if (UIConfiguration) { + const joinWithColumns = UIConfiguration.find((item) => item.name === "microplanPreview")?.joinWithColumns; + setJoinByColumns(joinWithColumns); + } + let temp; + if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); + if (temp?.ruleConfigureOperators) { + setOperatorsObject(temp.ruleConfigureOperators); + } + if (microplanPreviewAggregatesList) setMicroplaPreviewAggregates(microplanPreviewAggregatesList); + }, []); + + // UseEffect for checking completeness of data before moveing to next section + useEffect(() => { + if (!dataToShow || checkDataCompletion !== "true" || !setCheckDataCompletion) return; + const check = filterObjects(hypothesisAssumptionsList, microplanData?.hypothesis); + if (check.length === 0) { + if (navigationEvent?.name === "next") return setModal("confirm-microplan-generation"); + return createMicroplan(false, false); + } + setModal("confirm-apply-changed-hypothesis"); + }, [checkDataCompletion]); + + // check if data has changed or not + const updateData = useCallback( + (doPerform) => { + // Update the microplan data with selected hierarchy and resources + // This function also handles setting the completion check based on the action to be performed + if (!setMicroplanData) return; + try { + let tempData = filterMicroplanDataToShowWithHierarchySelection(data, {}, hierarchy); + // Adding resources to the data we need to show + tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( + tempData, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + userEditedResources, + t + ); + setMicroplanData((previous) => ({ + ...previous, + microplanPreview: { + previewData: tempData, + userEditedResources, + }, + })); + if (doPerform) { + return setCheckDataCompletion("perform-action"); + } + setCheckDataCompletion("false"); + } catch (error) { + console.error("Failed to update data:", error); + } + }, + [ + resources, + boundarySelections, + hierarchy, + hypothesisAssumptionsList, + formulaConfiguration, + userEditedResources, + setMicroplanData, + setCheckDataCompletion, + ] + ); + + const cancelUpdateData = useCallback(() => { + setUpdateHypothesis(false); + if (navigationEvent?.name === "next") setModal("confirm-microplan-generation"); + else createMicroplan(false, false); + }, [setCheckDataCompletion, setModal]); + + useEffect(() => { + if (boundarySelections && Object.values(boundarySelections).every((item) => item.length === 0) && hierarchy) { + const tempBoundarySelection = {}; + for (const item of hierarchy) { + tempBoundarySelection[item] = []; + } + setBoundarySelections(tempBoundarySelection); + } + }, [hierarchy]); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + setCheckDataCompletion("false"); + setModal("none"); + } + }; + + const cancleNavigation = () => { + if (navigationEvent?.name !== "next") setCheckDataCompletion("false"); + setModal("none"); + }; + + const createMicroplan = useCallback( + (doCreation, updateHypothesis) => { + if (!hypothesisAssumptionsList || !setMicroplanData) return; + const updateDataWrapper = () => { + if (doCreation || navigationEvent?.name !== "next") { + return updateData(true); + } + updateData(false); + }; + const setCheckDataCompletionWrapper = (value) => { + if (!doCreation) { + return setCheckDataCompletion("false"); + } + setCheckDataCompletion(value); + }; + const microData = updateHypothesis ? updateMicroplanData(hypothesisAssumptionsList) : microplanData; + setLoaderActivation(true); + updateHyothesisAPICall( + microData, + setMicroplanData, + operatorsObject, + microData?.microplanDetails?.name, + campaignId, + UpdateMutate, + setToast, + updateDataWrapper, + setLoaderActivation, + doCreation && navigationEvent?.name === "next" ? "GENERATED" : "DRAFT", + cancleNavigation, + state, + campaignType, + navigationEvent, + setCheckDataCompletionWrapper, + t + ); + + setUpdateHypothesis(false); + setModal("none"); + }, + [ + hypothesisAssumptionsList, + setMicroplanData, + operatorsObject, + campaignId, + UpdateMutate, + setToast, + updateData, + setLoaderActivation, + navigationEvent, + t, + ] + ); + + const updateMicroplanData = useCallback( + (hypothesisAssumptionsList) => { + let microData = {}; + setMicroplanData((previous) => { + microData = { ...previous, hypothesis: hypothesisAssumptionsList }; + return microData; + }); + return microData; + }, + [setMicroplanData] + ); + + // Set microplan preview data + useEffect(() => { + if (data?.length !== 0 || !hierarchyRawData || !hierarchy || validationSchemas?.length === 0) return; + + const combinedData = fetchMicroplanPreviewData(campaignType, microplanData, validationSchemas, hierarchy); + // process and form hierarchy + if (combinedData && hierarchy) { + const { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchyRawData, [combinedData]); + setBoundaryData({ Microplan: { hierarchyLists, hierarchicalData } }); + } + if (combinedData) { + setData(combinedData); + setDataToShow(combinedData); + } + }, [hierarchy, hierarchyRawData, microplanData]); + + useEffect(() => { + if (!boundarySelections && !resources) return; + let tempData = filterMicroplanDataToShowWithHierarchySelection(data, boundarySelections, hierarchy); + // Adding resources to the data we need to show + tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( + tempData, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + userEditedResources, + t + ); + setDataToShow(tempData); + setMicroplanData((previous) => ({ ...previous, microplanPreview: { ...previous.microplanPreview, previewData: tempData, userEditedResources } })); + }, [boundarySelections, resources, hypothesisAssumptionsList, userEditedResources]); + + if (isCampaignLoading || ishierarchyLoading) { + return ( +
+ +
+ ); + } + + return ( + <> +
+
+

{t(campaignData?.campaignName)}

+
{t(microplanData?.microplanDetails?.name)}
+

{t("MICROPLAN_PREVIEW_CREATE_BY", { username: userInfo?.name })}

+
+
+
+ +
+
+ +
+
+

{t("MICROPLAN_PREVIEW_HYPOTHESIS_HEADING")}

+

{t("MICROPLAN_PREVIEW_HYPOTHESIS_INSTRUCTIONS")}

+ +
+
+ {dataToShow?.length != 0 ? ( + + ) : ( +
{t("NO_DATA_AVAILABLE")}
+ )} +
+
+ {modal === "confirm-apply-changed-hypothesis" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={() => { + setUpdateHypothesis(true); + if (navigationEvent?.name === "next") setModal("confirm-microplan-generation"); + else createMicroplan(false, true); + }} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={cancelUpdateData} + formId="modal-action" + > + + + )} + {modal === "confirm-microplan-generation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={() => createMicroplan(true, updateHypothesis)} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={() => createMicroplan(false, updateHypothesis)} + formId="modal-action" + > +
+

{t("INSTRUCTIONS_MICROPLAN_GENERATION_CONFIRMATION")}

+
+
+ )} +
+ {loaderActivation && } + + ); +}; + +export default MicroplanPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js new file mode 100644 index 00000000000..e92335d6581 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js @@ -0,0 +1,434 @@ +import { CardLabel, Loader, MultiSelectDropdown, TextInput } from "@egovernments/digit-ui-components"; +import React, { memo, useCallback, useEffect, useMemo, useState, Fragment, useRef } from "react"; +import { fetchDropdownValues } from "../utils/processHierarchyAndData"; +import { CloseButton, ModalHeading } from "./CommonComponents"; +import { PRIMARY_THEME_COLOR, commonColumn } from "../configs/constants"; +import { Button, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import { useNumberFormatter } from "../hooks/useNumberFormatter"; +import { calculateAggregateValue, filterObjects, useHypothesis } from "../utils/microplanPreviewUtils"; + +export const HypothesisValues = memo(({ boundarySelections, hypothesisAssumptionsList, setHypothesisAssumptionsList, setToast, setModal, t }) => { + const [tempHypothesisList, setTempHypothesisList] = useState(hypothesisAssumptionsList || []); + const { valueChangeHandler } = useHypothesis(tempHypothesisList, hypothesisAssumptionsList); + const contentRef = useRef(null); + const [isScrollable, setIsScrollable] = useState(false); + + const applyNewHypothesis = () => { + if (tempHypothesisList.some((item) => item.active && (Number.isNaN(parseFloat(item.value)) || parseFloat(item.value) === 0))) { + setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") }); + return; + } + if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) + return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); + setHypothesisAssumptionsList(tempHypothesisList); + }; + const checkScrollbar = () => { + if (contentRef.current) { + setIsScrollable(contentRef.current.scrollHeight > contentRef.current.clientHeight); + } + }; + + useEffect(() => { + // Initial check + checkScrollbar(); + + // Check on resize + window.addEventListener("resize", checkScrollbar); + + // Cleanup event listeners on component unmount + return () => { + window.removeEventListener("resize", checkScrollbar); + }; + }, []); + + useEffect(() => { + const content = contentRef.current; + content.addEventListener("scroll", checkScrollbar); + + return () => { + content.removeEventListener("scroll", checkScrollbar); + }; + }, [contentRef]); + + return ( +
+
+ {tempHypothesisList + .filter((item) => item?.active) + ?.filter((item) => item.key !== "") + .map((item, index) => ( +
+

{t(item?.key)}

+
+ {/* Dropdown for boundaries */} + + valueChangeHandler({ item, newValue: value?.target?.value }, setTempHypothesisList, boundarySelections, setToast, t) + } + disable={false} + /> +
+
+ ))} +
+
+
+
+ ); +}); + +export const BoundarySelection = memo(({ boundarySelections, setBoundarySelections, boundaryData, hierarchy, t }) => { + const [processedHierarchy, setProcessedHierarchy] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [changedBoundaryType, setChangedBoundaryType] = useState(""); + + // Filtering out dropdown values + useEffect(() => { + if (!boundaryData || !hierarchy) return; + + const processedHierarchyTemp = fetchDropdownValues( + boundaryData, + processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, + boundarySelections, + changedBoundaryType + ); + setProcessedHierarchy(processedHierarchyTemp); + setIsLoading(false); + }, [boundaryData, hierarchy, boundarySelections]); + + return ( +
+ {isLoading && } + {processedHierarchy?.map((item, index) => ( +
+ {t(item?.boundaryType)} + {item?.parentBoundaryType === null ? ( + 5 ? { height: "13.75rem" } : {}} + type={"multiselectdropdown"} + t={t} + options={item?.dropDownOptions || []} + optionsKey="name" + addSelectAllCheck={true} + onSelect={(e) => { + setChangedBoundaryType(item?.boundaryType); + Digit.Utils.microplan.handleSelection( + e, + item?.boundaryType, + boundarySelections, + hierarchy, + setBoundarySelections, + boundaryData, + setIsLoading + ); + }} + /> + ) : ( + 5 ? { height: "13.75rem" } : {}} + type={"multiselectdropdown"} + t={t} + options={Digit.Utils.microplan.processDropdownForNestedMultiSelect(item?.dropDownOptions) || []} + optionsKey="name" + addSelectAllCheck={true} + onSelect={(e) => { + setChangedBoundaryType(item?.boundaryType); + Digit.Utils.microplan.handleSelection( + e, + item?.boundaryType, + boundarySelections, + hierarchy, + setBoundarySelections, + boundaryData, + setIsLoading + ); + }} + variant="nestedmultiselect" + /> + )} +
+ ))} +
+ ); +}); + +export const DataPreview = memo( + ({ previewData, isCampaignLoading, ishierarchyLoading, resources, userEditedResources, setUserEditedResources, modal, setModal, data, t }) => { + if (!previewData) return; + const [tempResourceChanges, setTempResourceChanges] = useState(userEditedResources); + const [selectedRow, setSelectedRow] = useState(); + const conmmonColumnIndex = useMemo(() => { + return previewData?.[0]?.indexOf(commonColumn); + }, [previewData]); + if (isCampaignLoading || ishierarchyLoading) { + return ( +
+ +
+ ); + } + + const rowClick = useCallback((rowIndex) => { + setSelectedRow(rowIndex); + setModal("change-preview-data"); + }, []); + + const finaliseRowDataChange = () => { + setUserEditedResources(tempResourceChanges); + setModal("none"); + setSelectedRow(undefined); + }; + + const modalCloseHandler = () => { + setModal("none"); + setSelectedRow(undefined); + }; + + return ( +
+
+ + + + {previewData[0].map((header, columnIndex) => ( + + ))} + + + + {previewData.slice(1).map((rowData, rowIndex) => { + const rowDataList = Object.values(previewData[0]).map((header, cellIndex) => ( + + )); + return ( + { + rowClick(rowIndex + 1); + }} + // style={{...(userEditedResources?.[rowData?.[conmmonColumnIndex]] && Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !==0 + // ? { borderL: "1px solid rgba(244, 119, 56, 0.12)" } + // : {}),}} + > + {rowDataList} + + ); + })} + +
+ {t(header)} +
+ {cellIndex === 0 && + userEditedResources?.[rowData?.[conmmonColumnIndex]] && + Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !== 0 &&
} + + {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : t("NO_DATA")} +
+
+ {modal === "change-preview-data" && ( +
+ } + headerBarEnd={} + actionCancelLabel={t("CANCLE")} + actionCancelOnSubmit={modalCloseHandler} + actionSaveLabel={t("SAVE_CHANGES")} + actionSaveOnSubmit={finaliseRowDataChange} + formId="modal-action" + > + + +
+ )} +
+ ); + } +); + +export const AppplyChangedHypothesisConfirmation = ({ newhypothesisList, hypothesisList, t }) => { + const data = filterObjects(newhypothesisList, hypothesisList); + return ( +
+
+

{t("INSTRUCTION_PROCEED_WITH_NEW_HYPOTHESIS")}

+
+ + {t("MICROPLAN_PREVIEW_HYPOTHESIS")} + +
+ + + + + + + + + + {data?.map((row, index) => ( + + + + + + ))} + +
{t("KEYS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
{t(row?.key)}{t(row?.oldValue)}{t(row?.value)}
+
+
+ ); +}; + +export const EditResourceData = ({ previewData, selectedRow, resources, tempResourceChanges, setTempResourceChanges, data, t }) => { + const conmmonColumnData = useMemo(() => { + const index = previewData?.[0]?.indexOf(commonColumn); + if (index === -1) return; + return previewData?.[selectedRow]?.[index]; + }, [previewData]); + + const valueChangeHandler = (item, value) => { + if (!conmmonColumnData) return; + if (isNaN(value) || (!isFinite(value) && value !== "")) return; + let changedDataAgainstBoundaryCode = tempResourceChanges?.[conmmonColumnData] || {}; + changedDataAgainstBoundaryCode[item] = value === "" ? undefined : parseFloat(value); + setTempResourceChanges((previous) => ({ ...previous, [conmmonColumnData]: changedDataAgainstBoundaryCode })); + }; + + return ( +
+ + + + + + + + + + {data[0].map((item) => { + let index = data?.[0]?.indexOf(item); + if (index === -1) return; + const currentData = data?.[selectedRow]?.[index]; + return ( + + + + + + ); + })} + {resources.map((item) => { + let index = previewData?.[0]?.indexOf(item); + if (index === -1) return; + const currentData = previewData?.[selectedRow]?.[index]; + + return ( + + + + + + ); + })} + +
{t("COLUMNS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
+

{t(item)}

+
+

{currentData || t("NO_DATA")}

+
+ +
+

{t(item)}

+
+

{currentData || t("NO_DATA")}

+
+ valueChangeHandler(item, value.target.value)} + /> +
+
+ ); +}; + +export const Aggregates = memo(({ microplanPreviewAggregates, dataToShow, NumberFormatMappingForTranslation, t }) => { + const { formatNumber } = useNumberFormatter(NumberFormatMappingForTranslation?.reduce((acc, obj) => Object.assign(acc, obj), {})); + + if (!microplanPreviewAggregates) return null; + return ( +
+ {microplanPreviewAggregates.map((item, index) => { + const aggregate = calculateAggregateValue(item, dataToShow); + return ( +
+

{isNaN(parseInt(aggregate)) ? 0 : formatNumber(parseInt(aggregate))}

+

{typeof item === "object" && item.name ? t(item.name) : t(item)}

+
+ ); + })} +
+ ); +}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js new file mode 100644 index 00000000000..9a1dd8f5500 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js @@ -0,0 +1,34 @@ +import { EmployeeModuleCard, WorksMgmtIcon } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useTranslation } from "react-i18next"; + +const ROLES = { + MICROPLAN: ["MICROPLAN_ADMIN"], +}; + +const MicroplanningCard = () => { + const { t } = useTranslation(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + + const generateLink = (labelKey, pathSuffix) => { + return { + label: t(labelKey), + link: `/${window?.contextPath}/employee/microplanning/${pathSuffix}`, + roles: ROLES.MICROPLAN, + }; + }; + + let links = [generateLink("CREATE_NEW_MICROPLAN", "select-campaign"), generateLink("OPEN_SAVED_MICROPLANS", "saved-microplans")]; + + links = links.filter((link) => (link?.roles && link?.roles?.length > 0 ? Digit.Utils.didEmployeeHasAtleastOneRole(link?.roles) : true)); + + const propsForModuleCard = { + Icon: , + moduleName: t("Microplanning"), + kpis: [], + links: links, + }; + return ; +}; + +export default MicroplanningCard; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js new file mode 100644 index 00000000000..2a35e9c0995 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js @@ -0,0 +1,29 @@ +import { Help, Tutorial, useTourState } from "@egovernments/digit-ui-react-components"; +import React, { Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { useLocation } from "react-router-dom"; +import { useMyContext } from "../utils/context"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +const MicroplanningHeader = () => { + const { tourState, setTourState } = useTourState(); + const { state } = useMyContext(); + const { t } = useTranslation(); + //using location.pathname we can update the stepIndex accordingly when help is clicked from any other screen(other than home screen) + const { pathname } = useLocation(); + + const startTour = () => { + if (state?.tourStateData) setTourState(state.tourStateData); + }; + + return ( + <> + +
+ +
+ + ); +}; + +export default MicroplanningHeader; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js new file mode 100644 index 00000000000..0792ee2e52d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js @@ -0,0 +1,158 @@ +import React, { useEffect } from "react"; +import { PopUp, HeaderBar, Toast, CloseButton, ButtonSelector } from "@egovernments/digit-ui-react-components"; +import { Close } from "@egovernments/digit-ui-svg-components"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +const Modal = ({ + headerBarMain, + headerBarEnd, + popupStyles, + children = {}, + actionCancelLabel, + actionCancelOnSubmit, + actionSaveLabel, + actionSaveOnSubmit, + error, + setError, + formId, + isDisabled, + hideSubmit, + style = {}, + footerLeftButtonstyle = {}, + footerRightButtonstyle = {}, + footerLeftButtonBody, + footerRightButtonBody, + popupModuleMianStyles, + headerBarMainStyle, + isOBPSFlow = false, + popupModuleActionBarStyles = {}, +}) => { + /** + * TODO: It needs to be done from the desgin changes + */ + const mobileView = Digit.Utils.browser.isMobile(); + useEffect(() => { + document.body.style.overflowY = "hidden"; + return () => { + document.body.style.overflowY = "auto"; + }; + }, []); + + return ( + +
+ +
+ {children} +
+ {actionCancelLabel || footerLeftButtonBody ? ( + 0 ? style : footerLeftButtonstyle} + /> + ) : null} + {!hideSubmit ? ( + 0 ? style : footerRightButtonstyle} + /> + ) : null} +
+
+
+ {error && setError(null)} type="error" />} +
+ ); +}; + +const moduleActionBarStyle = (isOBPSFlow, popupModuleActionBarStyles) => { + return isOBPSFlow + ? !mobileView + ? { marginRight: "18px" } + : { position: "absolute", bottom: "5%", right: "10%", left: window.location.href.includes("employee") ? "0%" : "7%" } + : popupModuleActionBarStyles; +}; + +// Wrapper for modal +export const ModalWrapper = ({ + closeModal, + LeftButtonHandler, + RightButtonHandler, + footerLeftButtonBody, + footerRightButtonBody, + header, + bodyText, + body, + popupStyles, + headerBarMainStyle, + popupModuleActionBarStyles, + hideSubmit, + closeButton = false, + actionCancelLabel, +}) => { + return ( + + {" "} + + + ) : ( + "" + ) + } + actionCancelOnSubmit={LeftButtonHandler} + actionSaveOnSubmit={RightButtonHandler} + formId="microplanning" + popupStyles={{ width: "33.375rem", borderRadius: "0.25rem", ...(popupStyles ? popupStyles : {}) }} + headerBarMainStyle={{ margin: 0, width: "33.375rem", overflow: "hidden", ...(headerBarMainStyle ? headerBarMainStyle : {}) }} + popupModuleMianStyles={{ margin: 0, padding: 0 }} + popupModuleActionBarStyles={popupModuleActionBarStyles ? popupModuleActionBarStyles : { justifyContent: "space-between", padding: "1rem" }} + style={{}} + hideSubmit={hideSubmit ? hideSubmit : false} + footerLeftButtonstyle={{ + padding: 0, + alignSelf: "flex-start", + height: "fit-content", + textStyles: { fontWeight: "600" }, + backgroundColor: "rgba(255, 255, 255, 1)", + color: PRIMARY_THEME_COLOR, + minWidth: "15.063rem", + border: `0.063rem solid ${PRIMARY_THEME_COLOR}`, + }} + footerRightButtonstyle={{ + padding: 0, + alignSelf: "flex-end", + height: "fit-content", + textStyles: { fontWeight: "500" }, + backgroundColor: PRIMARY_THEME_COLOR, + color: "rgba(255, 255, 255, 1)", + minWidth: "15.063rem", + boxShadow: "0px -2px 0px 0px rgba(11, 12, 12, 1) inset", + }} + footerLeftButtonBody={footerLeftButtonBody} + footerRightButtonBody={footerRightButtonBody} + actionCancelLabel={actionCancelLabel} + > + {bodyText && ( +
+

{bodyText}

+
+ )} + {body ? body : ""} +
+ ); +}; + +export default Modal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js new file mode 100644 index 00000000000..06d04ef2296 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js @@ -0,0 +1,272 @@ +import { ActionBar, Stepper, Toast } from "@egovernments/digit-ui-components"; +import PropTypes from "prop-types"; +import React, { useState, useEffect, useCallback } from "react"; +import { useTranslation } from "react-i18next"; +import { Button } from "@egovernments/digit-ui-react-components"; +import { ArrowBack, ArrowForward } from "@egovernments/digit-ui-svg-components"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; +import { memo } from "react"; + +/** + * + * @param { config: Object, checkDataCompleteness: boolean, components: Object, childProps: Object, stepNavigationActive: boolean, nextEventAddon: function, setCurrentPageExternally: function, completeNavigation } props + * @returns + * + */ +// Main component for creating a microplan +const Navigator = memo((props) => { + // States + const [currentPage, setCurrentPage] = useState(); + // const [toast, setToast] = useState(); + const [navigationEvent, setNavigationEvent] = useState(); + const [activeSteps, setActiveSteps] = useState(Digit.SessionStorage.get("microplanHelperData")?.activeSteps || -1); + /** + * checkDataCompletion + * "true": check for data completeness + * "false": do nothing + * "valid": data is present + * "invalid": whole or a part of the data is missing + * "perform-action": move to the respective step ( had to add this as mutate addons need some buffer time) + */ + const [checkDataCompletion, setCheckDataCompletion] = useState("false"); + + const { t } = useTranslation(); + + // Effect to set initial current page when timeline options change + useEffect(() => { + if (!props.config || props.config.length === 0) return; + let response; + if (props.setCurrentPageExternally) { + response = props.setCurrentPageExternally({ setCurrentPage, method: "set" }); + } + if (!response) setCurrentPage(props.config[0]); + }, [props.config]); + + // Might need it later + // Effect to handle data completion validation and show toast + useEffect(() => { + if (checkDataCompletion === "invalid") { + if (navigationEvent && navigationEvent.name === "next") { + props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") }); + } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step !== undefined) { + if (navigationEvent.step > currentPage.id) + props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") }); + else onStepClick(navigationEvent.step); + } else if (navigationEvent && navigationEvent.name === "previousStep") previousStep(); + setCheckDataCompletion("false"); + } + }, [checkDataCompletion]); + + // Effect to handle navigation events and transition between steps + useEffect(() => { + // if (checkDataCompletion !== "valid" || navigationEvent === undefined) return; + if ( + checkDataCompletion === "valid" && + ((navigationEvent.step && currentPage.id + 1 === navigationEvent.step) || currentPage.id > navigationEvent.step || !navigationEvent.step) + ) { + if (typeof props.nextEventAddon === "function") { + if (LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) + props.nextEventAddon(currentPage, checkDataCompletion, setCheckDataCompletion); + else props.nextEventAddon(currentPage, true, setCheckDataCompletion); + } else { + setCheckDataCompletion("perform-action"); + } + } + }, [navigationEvent, checkDataCompletion, props.nextEventAddon]); + + useEffect(() => { + handleNavigationEvent( + checkDataCompletion, + navigationEvent, + currentPage, + setCheckDataCompletion, + setNavigationEvent, + onStepClick, + nextStep, + previousStep, + props + ); + }, [checkDataCompletion, navigationEvent]); + + // Function to navigate to the next step + const nextStep = useCallback(() => { + if (!currentPage) return; + changeCurrentPage(props.config[currentPage?.id + 1]); + if (currentPage?.id + 1 > props.config.length - 1) return; + setCurrentPage((previous) => props.config[previous?.id + 1]); + }, [currentPage]); + + // Function to navigate to the previous step + const previousStep = useCallback(() => { + changeCurrentPage(props.config[currentPage?.id - 1]); + setCurrentPage((previous) => props.config[previous?.id - 1]); + }, [currentPage]); + + // Function to handle step click and navigate to the selected step + const onStepClick = useCallback((index) => { + const newCurrentPage = props.config.find((item) => item.id === index); + changeCurrentPage(newCurrentPage); + setCurrentPage(newCurrentPage); + }); + + // Function to handle next button click + const previousbuttonClickHandler = useCallback(() => { + if ( + (props.checkDataCompleteness && + props?.config[currentPage?.id]?.checkForCompleteness && + LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) || + currentPage?.id === props.config[props.config.length - 1].id + ) { + setNavigationEvent({ name: "previousStep" }); + setCheckDataCompletion("true"); + } else previousStep(); + }, [props.checkDataCompleteness, previousStep, setNavigationEvent]); + + // Function to handle next button click + const nextbuttonClickHandler = useCallback(() => { + if ( + props.checkDataCompleteness && + props?.config[currentPage?.id]?.checkForCompleteness && + LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null + ) { + setCheckDataCompletion("true"); + setNavigationEvent({ name: "next" }); + } else nextStep(); + }, [props.checkDataCompleteness, nextStep, setNavigationEvent]); + + // Function to handle step click + const stepClickHandler = useCallback( + (index) => { + if (index === currentPage?.id) return; + if (!props.stepNavigationActive) return; + if ( + (props.checkDataCompleteness && + props?.config[currentPage?.id]?.checkForCompleteness && + LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) || + currentPage?.id === props.config[props.config.length - 1].id + ) { + setCheckDataCompletion("true"); + setNavigationEvent({ name: "step", step: index }); + } else { + onStepClick(index); + } + }, + [props.checkDataCompleteness, props.stepNavigationActive, onStepClick] + ); + + // Function to set current page + const changeCurrentPage = (newPage) => { + if (props.setCurrentPageExternally) { + props.setCurrentPageExternally({ currentPage: newPage, method: "save" }); + } + }; + + const completeNavigation = () => { + setNavigationEvent({ name: "next" }); + setCheckDataCompletion("true"); + }; + + // changing active state + useEffect(() => { + if (currentPage?.id > activeSteps) { + setActiveSteps(currentPage?.id); + Digit.SessionStorage.set("microplanHelperData", { ...(Digit.SessionStorage.get("microplanHelperData") || {}), activeSteps: currentPage?.id }); + } + }, [currentPage]); + + return ( +
+ {/* Stepper component */} + t(item.name))} + direction="horizontal" + activeSteps={activeSteps >= 0 ? activeSteps + 1 : null} + onStepClick={stepClickHandler} + /> + + {/* Load custom component based on current page */} + {props?.components[currentPage?.component] ? ( + LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null ? ( + + ) : ( +
{t("COMMON_DATA_NOT_PRESENT")}
+ ) + ) : ( + "" + )} + + {/* Action bar */} + + {/* Back button */} + {currentPage?.id > 0 && ( + + +
+ ); +}); + +// Component to load custom component based on current page +const LoadCustomComponent = (props) => { + if (props && !props.component) return null; + const secondaryProps = props.secondaryProps; + return ; +}; +LoadCustomComponent.propTypes = { + component: PropTypes.elementType.isRequired, + secondaryProps: PropTypes.object, +}; + +const handleNavigationEvent = ( + checkDataCompletion, + navigationEvent, + currentPage, + setCheckDataCompletion, + setNavigationEvent, + onStepClick, + nextStep, + previousStep, + props +) => { + if (checkDataCompletion === "perform-action") { + if (navigationEvent && navigationEvent.name === "next") { + if (currentPage?.id === props.config.length - 1 && typeof props?.completeNavigation === "function") { + return props?.completeNavigation(); + } + nextStep(); + } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step !== undefined) onStepClick(navigationEvent.step); + else if (navigationEvent && navigationEvent.name === "previousStep") previousStep(); + setCheckDataCompletion("false"); + setNavigationEvent(undefined); + } +}; + +export default Navigator; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js new file mode 100644 index 00000000000..7ece3cce04d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js @@ -0,0 +1,876 @@ +import React, { useState, useEffect, useCallback, Fragment, useRef } from "react"; +import { useTranslation } from "react-i18next"; +import { Info, Trash } from "@egovernments/digit-ui-svg-components"; +import { ModalHeading } from "./CommonComponents"; +import { Button, Modal } from "@egovernments/digit-ui-react-components"; +import { Dropdown, InfoCard, Toast } from "@egovernments/digit-ui-components"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { v4 as uuidv4 } from "uuid"; +import { PlusWithSurroundingCircle } from "../icons/Svg"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +const page = "ruleEngine"; + +const RuleEngine = ({ + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + setToast, +}) => { + const { t } = useTranslation(); + + // States + const [editable, setEditable] = useState(true); + const [modal, setModalState] = useState("none"); + const [rules, setRules] = useState([]); + const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); + const [itemForDeletion, setItemForDeletion] = useState(); + const [exampleOption, setExampleOption] = useState(""); + const [inputs, setInputs] = useState([]); + const [outputs, setOutputs] = useState([]); + const [operators, setOperators] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [autofillData, setAutoFillData] = useState([]); + const { state, dispatch } = useMyContext(); + const [originalRuleOutputCount, setOriginalRuleOutputCount] = useState(0); + // const [toast, setToast] = useState(); + const [pureInputList, setPureInputList] = useState([]); + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + const setModal = (modalString) => { + const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); + elements.forEach((element) => { + element.classList.toggle("popup-wrap-rest-unfocus-active"); + }); + setModalState(modalString); + }; + + // UseEffect to extract data on first render + useEffect(() => { + if (pages) { + const previouspage = pages[currentPage?.id - 1]; + if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); + else setEditable(true); + } + }, []); + + // UseEffect for checking completeness of data before moveing to next section + useEffect(() => { + if (!rules || checkDataCompletion !== "true" || !setCheckDataCompletion) return; + // uncomment to activate data change save check + // if (!microplanData?.ruleEngine || !_.isEqual(rules, microplanData.ruleEngine)) setModal("data-change-check"); + // else + updateData(true); + }, [checkDataCompletion]); + + // UseEffect to store current data + useEffect(() => { + if (!rules || !setMicroplanData) return; + setMicroplanData((previous) => ({ ...previous, ruleEngine: rules })); + }, [rules]); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + // if (modal === "upload-guidelines") + setCheckDataCompletion("false"); + setModal("none"); + } + }; + + // check if data has changed or not + const updateData = useCallback( + (check) => { + if (!rules || !setMicroplanData) return; + if (check) { + setMicroplanData((previous) => ({ ...previous, ruleEngine: rules })); + const activeRules = rules.filter((item) => item.active); + const isValid = activeRules.every((item) => Object.values(item).every((data) => data !== "")) && activeRules.length !== 0; + if (isValid) setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } else { + let isValid = microplanData?.ruleEngine?.every((item) => Object.values(item).every((data) => data !== "")); + isValid = isValid && rules.length !== 0; + if (isValid) setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } + }, + [rules, setMicroplanData, microplanData, setCheckDataCompletion] + ); + + const cancelUpdateData = useCallback(() => { + setCheckDataCompletion(false); + setModal("none"); + }, [setCheckDataCompletion, setModal]); + + // useEffect to initialise the data from MDMS + useEffect(() => { + if (!state) return; + const schemas = state?.Schemas; + const hypothesisAssumptions = []; + microplanData?.hypothesis?.filter((item) => item.active).forEach((item) => (item.key !== "" ? hypothesisAssumptions.push(item.key) : null)); + const ruleConfigureOutput = state?.RuleConfigureOutput; + const UIConfiguration = state?.UIConfiguration; + const ruleConfigureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas) || []; + let AutoFilledRuleConfigurationsList = state?.AutoFilledRuleConfigurations; + AutoFilledRuleConfigurationsList = AutoFilledRuleConfigurationsList.find((item) => item.campaignType === campaignType)?.data; + microplanData?.ruleEngine?.forEach((item) => { + if (Object.values(item).every((e) => e !== "")) ruleConfigureInputs.push(item?.output); + }); + if (schemas) setValidationSchemas(schemas); + + let temp; + setHypothesisAssumptionsList(hypothesisAssumptions); + let outputs; + if (ruleConfigureOutput) temp = ruleConfigureOutput?.find((item) => item.campaignType === campaignType); + if (temp?.data) { + let data = temp.data; + setOriginalRuleOutputCount(data.length); + microplanData?.ruleEngine?.forEach((item) => { + if (item.active) { + const filteredData = data.filter((e) => e !== item?.output); + data = filteredData; + } + }); + outputs = data; + setOutputs(data); + } + + if (ruleConfigureInputs) setInputs(ruleConfigureInputs); + let operator; + if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); + if (temp?.ruleConfigureOperators) { + temp = temp.ruleConfigureOperators.map((item) => item.name); + operator = temp; + setOperators(temp); + } + // if (AutoFilledRuleConfigurationsList) setAutoFillData(AutoFilledRuleConfigurationsList); + // Pure inputs - output not there + const pureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas); + setPureInputList(pureInputs); + + const ssnRuleOutputs = microplanData?.ruleEngine?.reduce((acc, item) => { + if (item?.active && item?.output) acc.push(item?.output); + return acc; + }, []); + const tempOutput = [...outputs, ...(ssnRuleOutputs ? ssnRuleOutputs : [])]; + setExampleOption({ + output: tempOutput.length ? tempOutput[0] : "", + input: pureInputs.length ? pureInputs[0] : "", + operator: operator.length ? operator[0] : "", + assumptionValue: hypothesisAssumptions.length ? hypothesisAssumptions[0] : "", + }); + + let filteredRules = []; + let response; + if (microplanData?.ruleEngine && microplanData?.hypothesis) { + const hypothesisAssumptions = microplanData?.hypothesis?.filter((item) => item.active && item.key !== "").map((item) => item.key) || []; + if (hypothesisAssumptions.length !== 0) { + setHypothesisAssumptionsList(hypothesisAssumptions); + response = filterRulesAsPerConstrains( + microplanData.ruleEngine, + [], + hypothesisAssumptions, + tempOutput, + operator, + pureInputs, + setInputs, + setOutputs, + false + ); + filteredRules = response?.rules; + + // setRuleEngineDataFromSsn(microplanData.ruleEngine, hypothesisAssumptions, setRules); + } + } + if (response?.rulesDeleted) + setToast({ + state: "warning", + message: t("WARNING_RULES_DELETED_DUE_TO_PRIOR_SECTION_DATA_CHANGES"), + }); + if (!AutoFilledRuleConfigurationsList || !outputs || !hypothesisAssumptions || !schemas) return; + + response = filterRulesAsPerConstrains( + AutoFilledRuleConfigurationsList, + filteredRules, + hypothesisAssumptions, + outputs, + operator, + pureInputs, + setInputs, + setOutputs, + true + ); + + if (response?.rules) setRules(response?.rules); + }, []); + + const closeModal = useCallback(() => { + setModal("none"); + }, [setModal]); + + // Function to Delete an assumption + const deleteAssumptionHandlerCallback = useCallback(() => { + deleteAssumptionHandler(itemForDeletion, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList); + closeModal(); + }, [itemForDeletion, deleteAssumptionHandler, setItemForDeletion, setRules, setOutputs, setInputs, closeModal, pureInputList]); + + const sectionClass = `jk-header-btn-wrapper rule-engine-section ${editable ? "" : "non-editable-component"} popup-wrap-rest-unfocus`; + return ( + <> +
+
+
+ {/* NonInterractable Section */} + + {/* Interractable Section that includes the example as well as the rules */} + +
+ +
+
+ {/* delete conformation */} +
+ {modal === "delete-conformation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={deleteAssumptionHandlerCallback} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={closeModal} + > +
+

{t("RULE_ENGINE_INSTRUCTIONS_DELETE_ENTRY_CONFIRMATION")}

+
+
+ )} +
+ + ); +}; + +// Function to add a new assumption +const addRulesHandler = (setRules) => { + const uuid = uuidv4(); + setRules((previous) => [ + ...previous, + { + id: uuid, + // previous.length ? previous[previous.length - 1].id + 1 : 0, + output: "", + input: "", + operator: "", + assumptionValue: "", + active: true, + }, + ]); +}; + +// Defination for NonInterractable Section +const NonInterractableSection = React.memo(({ t }) => { + return ( +
+

{t("HEADING_RULE_ENGINE")}

+

{t("INSTRUCTION_RULE_ENGINE")}

+
+ ); +}); + +// Defination for NonInterractable Section +const InterractableSection = React.memo( + ({ + rules, + setRules, + hypothesisAssumptionsList, + setHypothesisAssumptionsList, + setModal, + setItemForDeletion, + exampleOption, + inputs, + outputs, + operators, + setInputs, + setOutputs, + setOperators, + pureInputList, + t, + }) => { + // References to the items in the list + const itemRefs = useRef([]); + // State to keep track of the currently expanded item index + const [expandedIndex, setExpandedIndex] = useState(null); + // Reference to the scroll container + const scrollContainerRef = useRef(null); + // State to track the render cycle count + const [renderCycle, setRenderCycle] = useState(0); + + // Effect to reset the render cycle count whenever the expandedIndex changes + useEffect(() => { + if (expandedIndex !== null) { + setRenderCycle(0); + } + }, [expandedIndex]); + + // Effect to handle scrolling to the expanded item after the DOM has updated + useEffect(() => { + if (renderCycle < 3) { + // Increment render cycle count to ensure multiple render checks + setRenderCycle((prev) => prev + 1); + } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { + try { + const parentElement = itemRefs.current[expandedIndex]; + const childElement = itemRefs.current[expandedIndex].children[1]; + + if (parentElement) { + const scrollContainer = scrollContainerRef.current; + const parentRect = parentElement.getBoundingClientRect(); + const containerRect = scrollContainer.getBoundingClientRect(); + + // Calculate the offset from the top of the container + const offset = parentRect.top - containerRect.top; + + // Scroll the container to the target position + scrollContainer.scrollTo({ + top: scrollContainer.scrollTop + offset - 100, + behavior: "smooth", + }); + } + + if (childElement) { + // Focus the child element if it exists + childElement.focus(); + } + } catch (error) { + console.error("Error scrolling to element:", error); + } + } + }, [renderCycle, expandedIndex]); + + // Effect to observe DOM changes in the expanded item and trigger render cycle + useEffect(() => { + if (expandedIndex !== null) { + const observer = new MutationObserver(() => { + setRenderCycle((prev) => prev + 1); + }); + + if (itemRefs.current[expandedIndex]) { + observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); + } + + return () => observer.disconnect(); + } + }, [expandedIndex]); + + // Function to toggle the expanded state of an item + const toggleExpand = (index) => { + setExpandedIndex(index === expandedIndex ? null : index); + }; + + // Handler for deleting an assumption on conformation + const deleteHandler = useCallback( + (item) => { + setModal("delete-conformation"); + setItemForDeletion(item); + }, + [setModal, setItemForDeletion] + ); + + return ( +
+ +
+
+
+

{t("VALUE")}

+
+
=
+
+

{t("RULE_ENGINE_INPUT")}

+
+
+

{t("RULE_ENGINE_OPERATOR")}

+
+
+

{t("KEY")}

+
+
+ +
+
+ {rules + .filter((item) => item.active) + .map((item, index) => ( +
{ + itemRefs.current[index] = el; + }} + onClick={() => toggleExpand(index)} + > +
+ +
+
+ +
+
+ +
+
+ ))} +
+
+ ); + } +); + +const Example = ({ exampleOption, t }) => { + return ( +
+
+

{t("EXAMPLE")}

+
+
+

{t("VALUE")}

+ +

{t("RULE_ENGINE_VALUE_HELP_TEXT")}

+
+ +
+

{"="}

+ +
=
+

{"="}

+
+ +
+

{t("RULE_ENGINE_INPUT")}

+ +

{t("RULE_ENGINE_INPUT_HELP_TEXT")}

+
+
+

{t("RULE_ENGINE_OPERATOR")}

+ +

{t("RULE_ENGINE_OPERATOR_HELP_TEXT")}

+
+
+

{t("KEY")}

+ +

{t("RULE_ENGINE_KEY_HELP_TEXT")}

+
+
+
+
+ +
+
+ ); +}; + +const deleteAssumptionHandler = (item, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList) => { + try { + const outputToRemove = []; + setRules((previous) => { + if (!previous.length) return []; + const deletionElementIndex = previous.findIndex((data) => data.id === item.id); + const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data)); + const newRules = filteredData.reduce((acc, dataItem, index) => { + if (dataItem.active) { + const possibleOutputs = acc.reduce((reducedData, element, index) => { + if (element.active && !Object.values(element).some((e) => e === "")) reducedData.push(element?.output); + return reducedData; + }, []); + possibleOutputs.push(...pureInputList); + if (!possibleOutputs.includes(dataItem?.input)) { + if (dataItem?.output !== "") outputToRemove.push(dataItem.output); + acc.push({ ...dataItem, input: "", oldInput: dataItem?.input ? dataItem?.input : dataItem?.oldInput }); + } else { + acc.push(dataItem); + } + } else { + acc.push(dataItem); + } + return acc; + }, []); + + return newRules || []; + }); + if (item?.output) { + setOutputs((previous) => { + if (!previous?.includes(item.output)) return previous ? [...previous, item.output] : [item.output]; + }); + setInputs((previous) => { + return previous?.filter((e) => e !== item.output && !outputToRemove.includes(e)); + }); + } + setItemForDeletion(); + } catch (error) { + console.error("Error while deleting a rule: ", error.message); + } +}; + +const Select = React.memo( + ({ item, rules, setRules, disabled = false, options, setOptions, toChange, unique, setInputs, outputs, pureInputList, t }) => { + const [selected, setSelected] = useState(""); + const [filteredOptions, setFilteredOptions] = useState([]); + + useEffect(() => { + if (item) { + if (outputs?.some((e) => e === item.input)) { + if (rules.filter((item) => item.active).some((e) => e?.output === item?.input)) setSelected({ code: item?.[toChange] }); + } else setSelected({ code: item[toChange] }); + } + }, [item]); + + useEffect(() => { + if (!options) return; + const filteredOptions = options.length ? options : []; + let filteredOptionPlaceHolder = []; + if (item?.[toChange] && !filteredOptions.includes(item[toChange])) { + filteredOptionPlaceHolder = [item[toChange], ...filteredOptions]; + } else filteredOptionPlaceHolder = filteredOptions; + + if (toChange === "input") { + const currentRuleIndex = rules.findIndex((e) => e?.id === item?.id); + filteredOptionPlaceHolder = filteredOptionPlaceHolder.filter((data) => { + let priorOutputs = []; + if (currentRuleIndex !== -1) { + priorOutputs = rules.reduce((acc, item, index) => { + if (item.active && index < currentRuleIndex) acc.push(item?.output); + return acc; + }, []); + } + priorOutputs.push(...pureInputList); + return data !== item.output && priorOutputs.includes(data); + }); + } + setFilteredOptions(filteredOptionPlaceHolder); + }, [options]); + + const selectChangeHandler = useCallback( + (e) => { + if (e.code === "SELECT_OPTION") return; + const existingEntry = rules.find((item) => item.active && item[toChange] === e.code); + if (existingEntry && unique) { + console.error("Attempted to add a duplicate entry where uniqueness is required."); + return; + } + const newDataSegment = { ...item }; + newDataSegment[toChange] = e.code; + setRules((previous) => { + const filteredAssumptionsList = previous.map((data) => { + if (data.id === item.id) return newDataSegment; + return data; + }); + return filteredAssumptionsList; + }); + if (typeof setInputs === "function") { + setInputs((previous) => { + let temp = _.cloneDeep(previous); + if (toChange === "output") { + temp = temp.filter((item) => item !== selected?.code); + } + if (!temp.includes(newDataSegment.output) && Object.values(newDataSegment).every((item) => item !== "")) + temp = [...temp, newDataSegment.output]; + + const currentRuleIndex = rules.findIndex((e) => e?.id === item?.id); + temp = temp.filter((data) => { + let priorOutputs = []; + if (currentRuleIndex !== -1) { + priorOutputs = rules.reduce((acc, item, index) => { + if (index < currentRuleIndex) acc.push(item?.output); + return acc; + }, []); + } + priorOutputs.push(...pureInputList); + return data !== item.output && priorOutputs.includes(data); + }); + return temp; + }); + } + if (unique) + setOptions((previous) => { + const newOptions = previous.filter((item) => item !== e.code); + if (selected?.code && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code); + return newOptions; + }); + }, + [rules, item, selected, setRules, setOptions, setInputs] + ); + + return ( + ({ code: item }))} + selected={selected} + select={selectChangeHandler} + optionKey="code" + placeholder={t("SELECT_OPTION")} + showToolTip={true} + /> + ); + } +); + +// get schema for validation +const getRuleConfigInputsFromSchema = (campaignType, microplanData, schemas) => { + if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; + const sortData = []; + if (!schemas) return; + for (const value of microplanData?.upload?.filter((value) => value?.active && value?.error === null) || []) { + sortData.push({ section: value?.section, fileType: value?.fileType }); + } + const filteredSchemas = + schemas?.filter((schema) => { + if (schema.campaignType) { + return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); + } + return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); + }) || []; + const finalData = filteredSchemas + ?.flatMap((item) => + Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRuleConfigureInputs) { + acc.push(key); + } + return acc; + }, []) + ) + .filter((item) => !!item); + return [...new Set(finalData)]; +}; + +// This function adding the rules configures in MDMS with respect to the canpaign when rule section is empty +const filterRulesAsPerConstrains = (autofillData, rules, hypothesisAssumptionsList, outputs, operators, inputs, setInputs, setOutputs, autofill) => { + if (rules && rules.filter((item) => item.active).length !== 0) return { rules }; + + let wereRulesNotDeleted = true; + const newRules = []; + const ruleOuputList = rules ? rules.filter((item) => item.active).map((item) => item?.output) : []; + let rulePlusInputs; + if (ruleOuputList) rulePlusInputs = [...inputs, ...ruleOuputList]; + else rulePlusInputs = inputs; + for (const item of autofillData) { + let active = !(item && item.active === false); + const ruleNotCompleteCheck = (!autofill && item && Object.values(item).filter((e) => e === "").length === 0) || autofill; + if ( + (ruleOuputList?.includes(item?.output) || + (outputs && !outputs.includes(item?.output)) || + (rulePlusInputs && !rulePlusInputs.includes(item?.input)) || + (operators && !operators.includes(item?.operator)) || + (hypothesisAssumptionsList && !hypothesisAssumptionsList.includes(item?.assumptionValue)) || + !outputs || + !rulePlusInputs || + !operators || + !hypothesisAssumptionsList) && + ruleNotCompleteCheck + ) { + if (autofill) { + continue; + } + if (active) { + wereRulesNotDeleted = false; + active = false; + } + } + if (!item["id"]) { + const uuid = uuidv4(); + item["id"] = uuid; + } + item.active = active; + newRules.push(item); + if (active && ruleNotCompleteCheck) { + rulePlusInputs?.push(item?.output); + ruleOuputList?.push(item?.output); + } + } + if (newRules.length !== 0) { + let newOutputs = []; + outputs.forEach((e) => { + if (!ruleOuputList.includes(e)) { + newOutputs.push(e); + } + }); + setOutputs(newOutputs); + setInputs(rulePlusInputs); + // setRules((previous) => [...previous, ...newRules]); + } + + return { rules: [...(rules ? rules : []), ...newRules], rulesDeleted: !autofill && !wereRulesNotDeleted }; +}; + +export default RuleEngine; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js new file mode 100644 index 00000000000..e6309dd74f3 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js @@ -0,0 +1,1137 @@ +import React, { useState, useEffect, useMemo, Fragment, useCallback } from "react"; +import { useTranslation } from "react-i18next"; +import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import { ModalWrapper } from "./Modal"; +import { geojsonPropertiesValidation } from "../utils/geojsonValidations"; +import { SpatialDataPropertyMapping } from "./resourceMapping"; +import { JsonPreviewInExcelForm } from "./JsonPreviewInExcelForm"; +import { ButtonType1, ButtonType2, CloseButton, ModalHeading } from "./CommonComponents"; +import { Loader } from "@egovernments/digit-ui-components"; +import { EXCEL, FILE_STORE, GEOJSON, PRIMARY_THEME_COLOR, SHAPEFILE } from "../configs/constants"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { v4 as uuidv4 } from "uuid"; +import { + handleExcelFile, + validateNamingConvention, + findReadMe, + downloadTemplate, + getSchema, + prepareExcelFileBlobWithErrors, + boundaryDataGeneration, + handleGeojsonFile, + handleShapefiles, + convertToSheetArray, + findGuideLine, + delay, +} from "../utils/uploadUtils"; +import { UploadGuideLines, UploadedFile, FileUploadComponent, UploadComponents, UploadInstructions, UploadSection } from "./UploadHelperComponents"; + +const page = "upload"; + +const Upload = ({ + MicroplanName = "default", + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + navigationEvent, + setToast, +}) => { + const { t } = useTranslation(); + + // States + const [editable, setEditable] = useState(true); + const [sections, setSections] = useState([]); + const [selectedSection, setSelectedSection] = useState(null); + const [modal, setModalState] = useState("none"); + const [selectedFileType, setSelectedFileType] = useState(null); + const [dataPresent, setDataPresent] = useState(false); + const [dataUpload, setDataUpload] = useState(false); + const [loader, setLoader] = useState(false); + const [fileData, setFileData] = useState(); + const [uploadedFileError, setUploadedFileError] = useState(); + const [fileDataList, setFileDataList] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [template, setTemplate] = useState([]); + const [resourceMapping, setResourceMapping] = useState([]); + const [previewUploadedData, setPreviewUploadedData] = useState(); + const { state, dispatch } = useMyContext(); + + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + + // request body for boundary hierarchy api + const reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getCurrentTenantId(), + hierarchyType: campaignData?.hierarchyType, + // hierarchyType: "Microplan", + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return ( + data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map( + (item) => `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}` + ) || {} + ); + }, + }, + }; + const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, [t]); + + const setModal = (modalString) => { + const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); + elements.forEach((element) => { + element.classList.toggle("popup-wrap-rest-unfocus-active"); + }); + setModalState(modalString); + }; + + // UseEffect for checking completeness of data before moveing to next section + useEffect(() => { + if (!fileDataList || checkDataCompletion !== "true" || !setCheckDataCompletion) return; + updateData(true); + }, [checkDataCompletion]); + + // UseEffect to store current data + useEffect(() => { + if (!fileDataList || !setMicroplanData) return; + setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); + }, [fileDataList]); + + // check if data has changed or not + const updateData = useCallback( + (check) => { + if (!fileDataList || !setMicroplanData) return; + + // if user has selected a file type and wants to go back to file type selection he/she can click back buttom + const currentSectionIndex = sections.findIndex((item) => item.id === selectedSection.id); + if (!dataPresent) { + if (navigationEvent?.name !== "step") { + if (navigationEvent?.name === "next") { + if (currentSectionIndex < sections.length - 1) { + setSelectedSection(sections[currentSectionIndex + 1]); + setCheckDataCompletion("false"); + return; + } + } else if (navigationEvent?.name === "previousStep") { + if (dataUpload) { + setDataUpload(false); + setSelectedFileType(null); + setCheckDataCompletion("false"); + return; + } + if (currentSectionIndex > 0) { + setSelectedSection(sections[currentSectionIndex - 1]); + setCheckDataCompletion("false"); + return; + } + } + } + } else { + if (navigationEvent?.name === "next") { + if (currentSectionIndex < sections.length - 1) { + setSelectedSection(sections[currentSectionIndex + 1]); + setCheckDataCompletion("false"); + return; + } + } else if (navigationEvent?.name === "previousStep") { + if (currentSectionIndex > 0) { + setSelectedSection(sections[currentSectionIndex - 1]); + setCheckDataCompletion("false"); + return; + } + } + } + + if (check) { + setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); + const valueList = fileDataList ? fileDataList : []; + const sectionCheckList = sections?.filter((item) => item.required); + + if ( + valueList.length !== 0 && + sectionCheckList.every((item) => { + const filteredList = fileDataList?.filter((e) => e.active && e.templateIdentifier === item.id); + if (filteredList?.length === 0) return false; + return filteredList?.every((element) => element?.error === null) && fileDataList && !fileDataList.some((e) => e?.active && e?.error); + }) + ) + setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } else { + const valueList = microplanData?.Upload ? Object.values(microplanData?.Upload) : []; + if ( + valueList.length !== 0 && + sectionCheckList.every((item) => + fileDataList?.filter((e) => e.templateIdentifier === item.id)?.every((element) => element.active && element?.error === null) + ) + ) + setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } + }, + [fileDataList, setMicroplanData, microplanData, setCheckDataCompletion, dataPresent, dataUpload, navigationEvent] + ); + + // UseEffect to extract data on first render + useEffect(() => { + if (microplanData?.upload) { + setFileDataList(microplanData.upload); + } + + if (pages) { + const previouspage = pages[currentPage?.id - 1]; + if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); + else setEditable(true); + } + }, []); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal, previewUploadedData]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + if (modal === "upload-guidelines") { + setModal("none"); + } + if (previewUploadedData) setPreviewUploadedData(undefined); + } + }; + + // Effect to update sections and selected section when data changes + useEffect(() => { + if (state) { + const uploadSections = state?.UploadConfiguration; + const schemas = state?.Schemas; + if (schemas) setValidationSchemas(schemas); + if (uploadSections) { + setSelectedSection(uploadSections.length > 0 ? uploadSections[0] : null); + setSections(uploadSections); + } + } + }, []); + + // Memoized section options to prevent unnecessary re-renders + const sectionOptions = useMemo(() => { + if (!sections) return []; + return sections.map((item) => ( + e.active && e.templateIdentifier === item.id && !e.error)?.length !== 0} + /> + )); + }, [sections, selectedSection, fileDataList]); + + const showDownloadTemplate = () => { + if (selectedSection?.UploadFileTypes) { + const schema = getSchema(campaignType, selectedFileType?.id, selectedSection.id, validationSchemas); + if (schema?.template?.showTemplateDownload) return true; + } + return false; + }; + + // Handler for when a file type is selected for uplaod + const selectFileTypeHandler = (e) => { + if (selectedSection?.UploadFileTypes) { + const schema = getSchema(campaignType, e.target.name, selectedSection.id, validationSchemas); + setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item.id === e.target.name)); + if (schema?.template?.showTemplateDownload) setModal("upload-modal"); + else UploadFileClickHandler(false); + return; + } + setToast({ + state: "error", + message: t("ERROR_UNKNOWN"), + }); + setLoader(false); + return; + }; + + // Memoized section components to prevent unnecessary re-renders + const sectionComponents = useMemo(() => { + if (!sections) return; + return sections.map((item) => ( + + )); + }, [sections, selectedSection, selectedFileType]); + + // Close model click handler + const closeModal = () => { + setResourceMapping([]); + setModal("none"); + }; + + // handler for show file upload screen + const UploadFileClickHandler = (download = false) => { + if (download) { + downloadTemplateHandler(); + } + setModal("none"); + setDataUpload(true); + }; + const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); + const downloadTemplateHandler = () => { + const downloadParams = { + campaignType, + type: selectedFileType.id, + section: selectedSection.id, + setToast, + campaignData, + hierarchyType: campaignData?.hierarchyType, + Schemas: validationSchemas, + HierarchyConfigurations: state?.HierarchyConfigurations, + setLoader, + hierarchy, + readMeData: state?.ReadMeData, + readMeSheetName: readMeConstant ? readMeConstant.value : undefined, + t, + }; + downloadTemplate(downloadParams); + }; + // Effect for updating current session data in case of section change + useEffect(() => { + if (selectedSection) { + let file = fileDataList?.find((item) => item.active && item.templateIdentifier === selectedSection.id); + if (file?.resourceMapping) { + setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item?.id === file?.fileType)); + setUploadedFileError(file?.error); + setFileData(file); + setDataPresent(true); + } else { + resetSectionState(); + } + } else { + resetSectionState(); + } + }, [selectedSection]); + + const resetSectionState = () => { + setUploadedFileError(null); + setSelectedFileType(null); + setDataPresent(false); + setResourceMapping([]); + setDataUpload(false); + }; + + // Function for handling upload file event + const UploadFileToFileStorage = async (file) => { + if (!file) return; + try { + // setting loader + setLoader("FILE_UPLOADING"); + let check; + let fileDataToStore; + let errorMsg; + let errorLocationObject; // object containing the location and type of error + let response; + let callMapping = false; + // Checking if the file follows name convention rules + if (!validateNamingConvention(file, selectedFileType["namingConvention"], setToast, t)) { + setLoader(false); + return; + } + + let schemaData; + if (selectedFileType.id !== SHAPEFILE) { + // Check if validation schema is present or not + schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + if (!schemaData) { + setToast({ + state: "error", + message: t("ERROR_VALIDATION_SCHEMA_ABSENT"), + }); + setLoader(false); + return; + } + } + let resourceMappingData = []; + let additionalSheets = []; + // Handling different filetypes + switch (selectedFileType.id) { + case EXCEL: + // let response = handleExcelFile(file,schemaData); + try { + response = await handleExcelFile( + file, + schemaData, + hierarchy, + selectedFileType, + {}, + setUploadedFileError, + t, + campaignData, + state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value + ); + check = response.check; + errorMsg = response.errorMsg; + errorLocationObject = response.errors; + fileDataToStore = response.fileDataToStore; + resourceMappingData = response?.tempResourceMappingData || []; + additionalSheets = response?.additionalSheets; + if (check === true) { + if (response?.toast) setToast(response.toast); + else setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); + } else if (response.toast) { + setToast(response.toast); + } else { + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + } + if (response.interruptUpload) { + setLoader(false); + return; + } + } catch (error) { + console.error("Excel parsing error", error.message); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); + return; + } + break; + case GEOJSON: + try { + response = await handleGeojsonFile(file, schemaData, setUploadedFileError, t); + file = new File([file], file.name, { type: "application/geo+json" }); + if (response.check === false && response.stopUpload) { + setLoader(false); + setToast(response.toast); + return; + } + check = response.check; + errorMsg = response.error; + fileDataToStore = response.fileDataToStore; + callMapping = true; + } catch (error) { + // console.error("Geojson parsing error", error.message); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); + return; + } + break; + case SHAPEFILE: + try { + response = await handleShapefiles(file, schemaData, setUploadedFileError, selectedFileType, setToast, t); + file = new File([file], file.name, { type: "application/octet-stream" }); + check = response.check; + errorMsg = response.error; + fileDataToStore = response.fileDataToStore; + callMapping = true; + } catch (error) { + console.error("Shapefile parsing error", error.message); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); + return; + } + break; + default: + setToast({ + state: "error", + message: t("ERROR_UNKNOWN_FILETYPE"), + }); + setLoader(false); + return; + } + let filestoreId; + if (!errorMsg && !callMapping) { + try { + const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, file, Digit.ULBService.getCurrentTenantId()); + if (filestoreResponse?.data?.files?.length > 0) { + filestoreId = filestoreResponse?.data?.files[0]?.fileStoreId; + } else { + errorMsg = t("ERROR_UPLOADING_FILE"); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setFileData((previous) => ({ ...previous, error: errorMsg })); + setUploadedFileError(errorMsg); + } + } catch (errorData) { + console.error(errorData.message); + errorMsg = t("ERROR_UPLOADING_FILE"); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setUploadedFileError(errorMsg); + handleValidationErrorResponse(t("ERROR_UPLOADING_FILE")); + return; + } + } + + if (selectedFileType.id === EXCEL) { + resourceMappingData = resourceMappingData.map((item) => ({ ...item, filestoreId })); + } + const uuid = uuidv4(); + // creating a fileObject to save all the data collectively + let fileObject = { + id: uuid, + templateIdentifier: `${selectedSection.id}`, + fileName: file.name, + section: selectedSection.id, + fileType: selectedFileType.id, + data: fileDataToStore, + file, + error: errorMsg ? errorMsg : null, + filestoreId, + resourceMapping: resourceMappingData, + active: true, + additionalSheets, + errorLocationObject, // contains location and type of error + }; + setFileDataList((prevFileDataList) => { + let temp = _.cloneDeep(prevFileDataList); + if (!temp) return temp; + let index = prevFileDataList?.findIndex((item) => item.active && item.templateIdentifier === selectedSection.id); + if (index !== -1) + temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; + temp.push(fileObject); + return temp; + }); + setFileData(fileObject); + if (errorMsg === undefined && callMapping) { + setModal("spatial-data-property-mapping"); + } + setDataPresent(true); + setLoader(false); + } catch (error) { + console.error(error.message); + console.error("File Upload error", error?.message); + setUploadedFileError("ERROR_UPLOADING_FILE"); + setLoader(false); + } + }; + + // Reupload the selected file + const reuplaodFile = () => { + setResourceMapping([]); + setFileData(undefined); + setDataPresent(false); + setUploadedFileError(null); + setDataUpload(false); + setSelectedFileType(null); + closeModal(); + }; + + const convertAndCombineFileData = () => { + let combinedData = fileData?.data ? Object.entries(fileData.data)?.map(([key, value]) => ({ sheetName: key, data: value })) : []; + if (fileData?.additionalSheets) { + for (const sheet of fileData.additionalSheets) { + if (sheet?.data && sheet.sheetName) { + const index = sheet?.position < combinedData.length && sheet.position !== -1 ? sheet.position : combinedData.length; + combinedData.splice(index, 0, sheet); + } + } + } + return combinedData; + }; + + // Function for creating blob out of data + const dataToBlob = async () => { + try { + let blob; + const schema = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + const filteredReadMeData = findReadMe(state?.ReadMeData, campaignType, selectedFileType.id, selectedSection.id); + let combinedData = convertAndCombineFileData(); + const readMeSheetName = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value; + switch (fileData.fileType) { + case EXCEL: + if (fileData?.errorLocationObject?.length !== 0) + blob = await prepareExcelFileBlobWithErrors( + combinedData, + fileData.errorLocationObject, + schema, + hierarchy, + filteredReadMeData, + readMeSheetName, + t + ); + else blob = fileData.file; + break; + case SHAPEFILE: + case GEOJSON: + if (fileData?.data) { + const result = convertToSheetArray(Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section)); + + if (fileData?.errorLocationObject?.length !== 0) + blob = await prepareExcelFileBlobWithErrors( + result, + fileData.errorLocationObject, + schema, + hierarchy, + filteredReadMeData, + readMeSheetName, + t + ); + } + break; + } + return blob; + } catch (error) { + console.error("Error generating blob:", error); + return; + } + }; + + // Download the selected file + const downloadFile = async () => { + setLoader("LOADING"); + try { + await delay(100); + let blob = await dataToBlob(); + if (blob) { + // Crating a url object for the blob + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + + // Forming a name for downloaded file + let fileNameParts = fileData.fileName.split("."); + fileNameParts.pop(); + fileNameParts.push("xlsx"); + fileNameParts.join("."); + + //Downloading the file + link.download = fileNameParts.join("."); + link.click(); + URL.revokeObjectURL(url); + } else { + let downloadUrl = await Digit.UploadServices.Filefetch([fileData.filestoreId], Digit.ULBService.getCurrentTenantId()); + const link = document.createElement("a"); + link.href = downloadUrl; + // Forming a name for downloaded file + let fileNameParts = fileData.fileName.split("."); + fileNameParts.pop(); + fileNameParts.push("xlsx"); + fileNameParts.join("."); + link.download = fileNameParts; // Replace with the desired file name and extension + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + } catch (error) { + console.error(error.message); + setToast({ + state: "error", + message: t("ERROR_UNKNOWN_ERROR"), + }); + } + setLoader(false); + }; + + // delete the selected file + const deleteFile = () => { + setResourceMapping([]); + setFileDataList((previous) => { + let temp = _.cloneDeep(previous); + if (!temp) return temp; + let index = temp?.findIndex((item) => { + return item.id === fileData.id; + }); + if (index !== -1) + temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; + return temp; + }); + setFileData(undefined); + setDataPresent(false); + setUploadedFileError(null); + setDataUpload(false); + setSelectedFileType(null); + closeModal(); + }; + + // Function for handling the validations for geojson and shapefiles after mapping of properties + const validationForMappingAndDataSaving = async () => { + try { + setLoader("LOADING"); + const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + let error; + if (!checkForSchemaData(schemaData)) return; + const { data, valid, errors } = computeMappedDataAndItsValidations(schemaData); + error = errors; + if (!valid) return; + let filestoreId; + if (!error) { + filestoreId = await saveFileToFileStore(); + } + let resourceMappingData; + if (filestoreId) { + resourceMappingData = resourceMapping.map((item) => { + return { ...item, filestoreId }; + }); + } + setResourceMapping([]); + + let boundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; + const mappedToList = resourceMappingData.map((item) => item.mappedTo); + if (hierarchy.every((item) => !mappedToList.includes(t(item)))) { + data.features.forEach((feature) => { + const boundaryCode = feature.properties.boundaryCode; + let additionalDetails = {}; + for (let i = 0; i < hierarchy.length; i++) { + if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { + additionalDetails[hierarchy[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; + } else { + additionalDetails[hierarchy[i]] = ""; + } + } + feature.properties = { ...additionalDetails, ...feature.properties }; + }); + } + + let fileObject = _.cloneDeep(fileData); + fileObject = { ...fileData, data, resourceMapping: resourceMappingData, error: error ? error : null, filestoreId }; + setFileData(fileObject); + setFileDataList((prevFileDataList) => { + let temp = _.cloneDeep(prevFileDataList); + if (!temp) return temp; + let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); + if (index !== -1) temp[index] = fileObject; + // temp.push(fileObject); + return temp; + }); + + setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); + setLoader(false); + } catch (error) { + console.error(error.message); + setUploadedFileError(t("ERROR_UPLOADING_FILE")); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setLoader(false); + handleValidationErrorResponse("ERROR_UPLOADING_FILE"); + } + }; + const saveFileToFileStore = async () => { + try { + const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, fileData.file, Digit.ULBService.getCurrentTenantId()); + if (filestoreResponse?.data?.files?.length > 0) { + return filestoreResponse?.data?.files[0]?.fileStoreId; + } + error = t("ERROR_UPLOADING_FILE"); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setResourceMapping([]); + setUploadedFileError(error); + } catch (errorData) { + console.error("Error while uploading file to filestore: ", errorData?.message); + let error = t("ERROR_UPLOADING_FILE"); + handleValidationErrorResponse(error); + setResourceMapping([]); + return; + } + }; + const computeMappedDataAndItsValidations = (schemaData) => { + const data = computeGeojsonWithMappedProperties(); + const response = geojsonPropertiesValidation(data, schemaData.schema, fileData?.section, t); + if (!response.valid) { + handleValidationErrorResponse(response.message, response.errors); + return { data: data, errors: response.errors, valid: response.valid }; + } + return { data: data, valid: response.valid }; + }; + + const handleValidationErrorResponse = (error, errorLocationObject = {}) => { + const fileObject = fileData; + if (fileObject) { + fileObject.error = [error]; + if (errorLocationObject) fileObject.errorLocationObject = errorLocationObject; + setFileData((previous) => ({ ...previous, error, errorLocationObject })); + setFileDataList((prevFileDataList) => { + let temp = _.cloneDeep(prevFileDataList); + if (!temp) return temp; + let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); + temp[index] = fileObject; + return temp; + }); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + if (error) setUploadedFileError(error); + } + setLoader(false); + }; + + const checkForSchemaData = (schemaData) => { + if (resourceMapping?.length === 0) { + setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); + setLoader(false); + return false; + } + + if (!schemaData || !schemaData.schema || !schemaData.schema["Properties"]) { + setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") }); + setLoader(false); + return; + } + + let columns = []; + if (schemaData?.doHierarchyCheckInUploadedData) { + columns.push(...hierarchy); + } + columns.push( + ...Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRequired) { + acc.push(key); + } + return acc; + }, []) + ); + + const resourceMappingLength = resourceMapping.filter((e) => !!e?.mappedFrom && columns.includes(e?.mappedTo)).length; + if (resourceMappingLength !== columns?.length) { + setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); + setLoader(false); + return false; + } + setModal("none"); + return true; + }; + + const computeGeojsonWithMappedProperties = () => { + const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + let schemaKeys; + if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"])); + // Sorting the resourceMapping list inorder to maintain the column sequence + const sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); + // Creating a object with input data with MDMS keys + const newFeatures = fileData.data["features"].map((item) => { + let newProperties = {}; + + sortedSecondList.forEach((e) => { + newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; + }); + item["properties"] = newProperties; + return item; + }); + let data = fileData.data; + data["features"] = newFeatures; + return data; + }; + + // Handler for checing file extension and showing errors in case it is wrong + const onTypeErrorWhileFileUpload = () => { + switch (selectedFileType.id) { + case EXCEL: + setToast({ state: "error", message: t("ERROR_EXCEL_EXTENSION") }); + break; + case GEOJSON: + setToast({ state: "error", message: t("ERROR_GEOJSON_EXTENSION") }); + break; + case SHAPEFILE: + setToast({ state: "error", message: t("ERROR_SHAPE_FILE_EXTENSION") }); + break; + } + }; + + // Cancle mapping and uplaod in case of geojson and shapefiles + const cancelUpload = () => { + setFileDataList((previous) => { + let temp = previous?.filter((item) => item.id !== fileData?.id); + return temp; + }); + setFileData(undefined); + setDataPresent(false); + setUploadedFileError(null); + setDataUpload(false); + setSelectedFileType(null); + closeModal(); + }; + + const openDataPreview = () => { + let data; + switch (fileData.fileType) { + case EXCEL: + data = fileData.data; + break; + case SHAPEFILE: + case GEOJSON: + if (!fileData || !fileData.data) { + setToast({ + state: "error", + message: t("ERROR_DATA_NOT_PRESENT"), + }); + return; + } + data = Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section); + break; + } + if (!data || Object.keys(data).length === 0) { + setToast({ + state: "error", + message: t("ERROR_DATA_NOT_PRESENT"), + }); + return; + } + setPreviewUploadedData(data); + }; + + if (isCampaignLoading || ishierarchyLoading) { + return ( +
+ +
+ ); + } + + return ( + <> +
+
+
+ {!dataPresent ? ( + dataUpload ? ( +
+ e.id === selectedSection.id)[0]} + selectedSection={selectedSection} + selectedFileType={selectedFileType} + UploadFileToFileStorage={UploadFileToFileStorage} + onTypeError={onTypeErrorWhileFileUpload} + downloadTemplateHandler={downloadTemplateHandler} + showDownloadTemplate={showDownloadTemplate} + /> +
+ ) : ( +
{sectionComponents}
+ ) + ) : ( +
+ {selectedSection != null && fileData !== null && ( + { + setModal("reupload-conformation"); + }} + DownloadFile={downloadFile} + DeleteFile={() => { + setModal("delete-conformation"); + }} + error={uploadedFileError} + openDataPreview={openDataPreview} + downloadTemplateHandler={downloadTemplateHandler} + showDownloadTemplate={showDownloadTemplate} + /> + )} +
+ )} + {!dataPresent && dataUpload && ( + { + setModal("upload-guidelines"); + }} + t={t} + /> + )} +
+ +
{sectionOptions}
+
+ +
+ {modal === "upload-modal" && ( + { + closeModal(); + setSelectedFileType(null); + }} + LeftButtonHandler={() => UploadFileClickHandler(false)} + RightButtonHandler={() => UploadFileClickHandler(true)} + sections={sections} + popupModuleActionBarStyles={{ + flex: 1, + justifyContent: "space-between", + padding: "1rem", + gap: "1rem", + }} + footerLeftButtonBody={} + footerRightButtonBody={} + header={ + + } + bodyText={t(`INSTRUCTIONS_DOWNLOAD_TEMPLATE_FOR_${selectedSection.code}_${selectedFileType.code}`)} + /> + )} + {modal === "delete-conformation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={deleteFile} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={closeModal} + > +
+

{t("INSTRUCTIONS_DELETE_FILE_CONFIRMATION")}

+
+
+ )} + {modal === "reupload-conformation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={reuplaodFile} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={closeModal} + > +
+

{t("INSTRUCTIONS_REUPLOAD_FILE_CONFIRMATION")}

+
+
+ )} + {modal === "spatial-data-property-mapping" && ( + } + actionSaveOnSubmit={validationForMappingAndDataSaving} + actionSaveLabel={t("COMPLETE_MAPPING")} + headerBarEnd={} + > +
+

{t("INSTRUCTION_SPATIAL_DATA_PROPERTY_MAPPING")}

+
+ +
+ )} + {modal === "upload-guidelines" && ( + + } + headerBarEnd={} + > + + + )} + {loader && } + + {previewUploadedData && ( +
+ setPreviewUploadedData(undefined)} + onDownload={downloadFile} + /> +
+ )} +
+
+ + ); +}; + +export default Upload; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js new file mode 100644 index 00000000000..5a520c4a1bd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js @@ -0,0 +1,299 @@ +import React, { useState, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import * as Icons from "@egovernments/digit-ui-svg-components"; +import { FileUploader } from "react-drag-drop-files"; +import { InfoButton, InfoCard } from "@egovernments/digit-ui-components"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +// Component for rendering individual section option +export const UploadSection = ({ item, selected, setSelectedSection, uploadDone }) => { + const { t } = useTranslation(); + // Handle click on section option + const handleClick = () => { + setSelectedSection(item); + }; + + return ( +
+
+ +
+

{t(item.code)}

+ {uploadDone && ( +
+ +
+ )} +
+ ); +}; + +export const UploadInstructions = ({ setModal, t }) => { + return ( + + {t("REFER")} +
+ {t("INFORMATION_DESCRIPTION_LINK")} +
+
, + ]} + /> + ); +}; + +// Component for rendering individual upload option +export const UploadComponents = ({ item, selected, uploadOptions, selectedFileType, selectFileTypeHandler }) => { + const { t } = useTranslation(); + const title = item.code; + + // Component for rendering individual upload option container + const UploadOptionContainer = ({ item, selectedFileType, selectFileTypeHandler }) => { + const [isHovered, setIsHovered] = useState(false); + + const handleMouseEnter = () => { + setIsHovered(true); + }; + + const handleMouseLeave = () => { + setIsHovered(false); + }; + + return ( +
+ +

{t(item.code)}

+ +
+ ); + }; + + return ( +
+
+
+

{t(`HEADING_UPLOAD_DATA_${title}`)}

+
+ +

{t(`INSTRUCTIONS_DATA_UPLOAD_OPTIONS_${title}`)}

+
+
+ {uploadOptions?.map((item) => ( + + ))} +
+
+ ); +}; + +// Component for uploading file +export const FileUploadComponent = ({ + selectedSection, + selectedFileType, + UploadFileToFileStorage, + section, + onTypeError, + downloadTemplateHandler, + showDownloadTemplate, +}) => { + if (!selectedSection || !selectedFileType) return
; + const { t } = useTranslation(); + let types; + section["UploadFileTypes"].forEach((item) => { + if (item.id === selectedFileType.id) types = item.fileExtension; + }); + return ( +
+
+
+

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

+ {showDownloadTemplate() && ( + + )} +
+

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

+ +
+ +
+ {t(`INSTRUCTIONS_UPLOAD_${selectedFileType.code}`)} 
{t("INSTRUCTIONS_UPLOAD_BROWSE_FILES")}
+
+
+
+
+
+ ); +}; + +// Component to display uploaded file +export const UploadedFile = ({ + selectedSection, + selectedFileType, + file, + ReuplaodFile, + DownloadFile, + DeleteFile, + error, + openDataPreview, + downloadTemplateHandler, + showDownloadTemplate, +}) => { + const { t } = useTranslation(); + const [errorList, setErrorList] = useState([]); + useEffect(() => { + let tempErrorList = []; + if (file?.errorLocationObject) { + for (const [sheetName, values] of Object.entries(file?.errorLocationObject)) { + for (const [row, columns] of Object.entries(values)) { + for (const [column, errors] of Object.entries(columns)) { + for (const error of errors) { + let convertedError; + if (typeof error === "object") { + let { error: actualError, ...otherProperties } = error; + convertedError = t(actualError, otherProperties?.values); + } else { + convertedError = t(error); + } + tempErrorList.push( + t("ERROR_UPLOAD_DATA_LOCATION_AND_MESSAGE", { + rowNumber: Number(row) + 1, + columnName: t(column), + error: convertedError, + sheetName: sheetName, + }) + ); + } + } + } + } + } + if (tempErrorList.length !== 0) { + setErrorList(tempErrorList); + } + }, [file]); + return ( +
+
+
+

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

+ {showDownloadTemplate() && ( + + )} +
+

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

+ +
+
+
+ +
+

{file.fileName}

+
+
+ + + +
+
+
+ {error && Array.isArray(error) && ( + , +
+ {error?.map((item) => { + if (item !== "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") { + return

{t(item)}

; + } + return null; + })} + {errorList.length !== 0 && errorList.map((item) =>

{item}

)} +
, + ]} + /> + )} +
+ ); +}; + +// Uplaod GuideLines +export const UploadGuideLines = ({ uploadGuideLines, t }) => { + const formMsgFromObject = (item) => { + if (!item?.hasLink) { + return t(item?.name); + } + return ( + <> + {t(item?.name)} {t(item?.linkName)}{" "} + + ); + }; + return ( +
+ {uploadGuideLines?.map((item, index) => ( +
+

+ {t(index + 1)}. +

+
+ {formMsgFromObject(item)} +
+
+ ))} +
+ ); +}; + +export const CustomIcon = (props) => { + if (!props.Icon) return null; + return ; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js new file mode 100644 index 00000000000..5a0cdabf735 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js @@ -0,0 +1,29 @@ +import React, { memo, useCallback } from "react"; +import { useTranslation } from "react-i18next"; + +const ZoomControl = memo(({ map, t }) => { + if (!map) return
{t("LOADING_MAP")}
; + + const zoomIn = useCallback(() => { + map.zoomIn(); + }, [map]); + + const zoomOut = useCallback(() => { + map.zoomOut(); + }, [map]); + + return ( +
+
+ + +
+
+ ); +}); + +export default ZoomControl; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js new file mode 100644 index 00000000000..df1eb78c135 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js @@ -0,0 +1,187 @@ +import { Dropdown } from "@egovernments/digit-ui-components"; +import { Table } from "@egovernments/digit-ui-react-components"; +import { PaginationFirst, PaginationLast, PaginationNext, PaginationPrevious } from "@egovernments/digit-ui-svg-components"; +import React, { useState, useEffect, useMemo, useRef, useCallback } from "react"; +const SCROLL_OFFSET = 100; + +export const SpatialDataPropertyMapping = ({ uploadedData, resourceMapping, setResourceMapping, schema, setToast, hierarchy, close, t }) => { + // If no data is uploaded, display a message + if (!uploadedData) return
{t("NO_DATA_TO_DO_MAPPING")}
; + + const itemRefs = useRef([]); + const [expandedIndex, setExpandedIndex] = useState(null); + // State to track the render cycle count + const [renderCycle, setRenderCycle] = useState(0); + const scrollContainerRef = useRef(null); + + // Effect to reset the render cycle count whenever the expandedIndex changes + useEffect(() => { + if (expandedIndex !== null) { + setRenderCycle(0); + } + }, [expandedIndex]); + + // Effect to handle scrolling to the expanded item after the DOM has updated + useEffect(() => { + if (renderCycle < 3) { + // Increment render cycle count to ensure multiple render checks + setRenderCycle((prev) => prev + 1); + } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { + try { + const parentElement = itemRefs.current[expandedIndex]; + const childElement = itemRefs.current[expandedIndex].children[1]; + + if (parentElement) { + const scrollContainer = scrollContainerRef.current; + const parentRect = parentElement.getBoundingClientRect(); + const containerRect = scrollContainer.getBoundingClientRect(); + + // Calculate the offset from the top of the container + const offset = parentRect.top - containerRect.top; + // Scroll the container to the target position + scrollContainer.scrollTo({ + top: scrollContainer.scrollTop + offset - SCROLL_OFFSET, + behavior: "smooth", + }); + } + + if (childElement) { + // Focus the child element if it exists + childElement.focus(); + } + } catch (error) { + console.error("Error scrolling to element:", error); + } + } + }, [renderCycle, expandedIndex]); + + // Effect to observe DOM changes in the expanded item and trigger render cycle + useEffect(() => { + if (expandedIndex !== null) { + const observer = new MutationObserver(() => { + setRenderCycle((prev) => prev + 1); + }); + + if (itemRefs.current[expandedIndex]) { + observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); + } + + return () => observer.disconnect(); + } + }, [expandedIndex]); + + // State variables + const [userColumns, setUserColumns] = useState([]); + const [templateColumns, setTemplateColumns] = useState([]); + + // Fetch template columns when schema changes + useEffect(() => { + if (!schema || !schema["schema"] || !schema.schema["Properties"]) + return setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") }); + + const columns = Object.keys(schema.schema["Properties"]); + if (columns) { + const newTemplateColumns = schema && !schema.doHierarchyCheckInUploadedData ? columns : [...hierarchy, ...columns]; + setTemplateColumns(newTemplateColumns); + } + }, [schema]); + + // Update user columns when uploaded data changes + useEffect(() => { + const userUploadedColumns = new Set(); + uploadedData?.["features"]?.forEach((item) => { + Object.keys(item["properties"]).forEach((key) => userUploadedColumns.add(key)); + }); + + //field level validations + for (const item of userUploadedColumns) { + if (item.length < 2) { + setToast({ state: "error", message: t("ERROR_FIELD_LENGTH") }); + close(); + } + } + setUserColumns((preUserColumns) => [...preUserColumns, ...userUploadedColumns]); + }, [uploadedData]); + + // Dropdown component for selecting user columns + const DropDownUserColumnSelect = ({ id, index }) => { + const [selectedOption, setSelectedOption] = useState(""); + useEffect(() => { + const obj = resourceMapping.find((item) => item["mappedTo"] === id); + if (obj) setSelectedOption({ code: obj["mappedFrom"] }); + else setSelectedOption(); + }, [id, resourceMapping]); + + const handleSelectChange = (event) => { + const newValue = event.code; + setSelectedOption(event); + setResourceMapping((previous) => { + const revisedData = previous.filter((item) => !(item["mappedTo"] === id || item["mappedFrom"] === newValue)); + return [...revisedData, { mappedTo: id, mappedFrom: newValue }]; + }); + }; + + const toggleExpand = (index) => { + setExpandedIndex(index === expandedIndex ? null : index); + }; + + return ( +
{ + itemRefs.current[index] = el; + }} + onClick={() => toggleExpand(index)} + onKeyDown={() => toggleExpand(index)} + > + ({ code: item }))} + selected={selectedOption} + optionKey="code" + select={handleSelectChange} + style={{ width: "100%", backgroundColor: "rgb(0,0,0,0)" }} + showToolTip={true} + /> +
+ ); + }; + + const tableColumns = useMemo( + () => [ + { + Header: t("COLUMNS_IN_TEMPLATE"), + accessor: "COLUMNS_IN_TEMPLATE", + }, + { + Header: t("COLUMNS_IN_USER_UPLOAD"), + accessor: "COLUMNS_IN_USER_UPLOAD", + Cell: ({ cell: { value }, row: { index } }) => + useMemo(() => , [value, index]), + }, + ], + [userColumns, setResourceMapping, resourceMapping, t, itemRefs] + ); + const data = useMemo(() => templateColumns.map((item) => ({ COLUMNS_IN_TEMPLATE: t(item), COLUMNS_IN_USER_UPLOAD: item })), [templateColumns]); + return ( +
+ { + return { style: {} }; + }} + getHeaderProps={(cellInfo) => { + return { style: {} }; + }} + /> + + ); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js new file mode 100644 index 00000000000..8f7fd717aba --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js @@ -0,0 +1,324 @@ +import _ from "lodash"; + +//create functions here based on module name set in mdms(eg->SearchProjectConfig) +//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] +// these functions will act as middlewares +// var Digit = window.Digit || {}; + +const businessServiceMap = { + "muster roll": "MR", +}; + +const inboxModuleNameMap = { + "muster-roll-approval": "muster-roll-service", +}; + +function filterUniqueByKey(arr, key) { + const uniqueValues = new Set(); + const result = []; + + arr.forEach((obj) => { + const value = obj[key]; + if (!uniqueValues.has(value)) { + uniqueValues.add(value); + result.push(obj); + } + }); + + return result; +} + +const epochTimeForTomorrow12 = () => { + const now = new Date(); + + // Create a new Date object for tomorrow at 12:00 PM + const tomorrowNoon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 12, 0, 0, 0); + + // Format the date as "YYYY-MM-DD" + const year = tomorrowNoon.getFullYear(); + const month = String(tomorrowNoon.getMonth() + 1).padStart(2, "0"); // Months are 0-indexed + const day = String(tomorrowNoon.getDate()).padStart(2, "0"); + + return Digit.Utils.date.convertDateToEpoch(`${year}-${month}-${day}`); +}; + +function cleanObject(obj) { + for (const key in obj) { + if (Object.hasOwn(obj, key)) { + if (Array.isArray(obj[key])) { + if (obj[key].length === 0) { + delete obj[key]; + } + } else if ( + obj[key] === undefined || + obj[key] === null || + obj[key] === false || + obj[key] === "" || // Check for empty string + (typeof obj[key] === "object" && Object.keys(obj[key]).length === 0) + ) { + delete obj[key]; + } + } + } + return obj; +} + +export const UICustomizations = { + businessServiceMap, + updatePayload: (applicationDetails, data, action, businessService) => { + if (businessService === businessServiceMap.estimate) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + estimate: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap.contract) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + contract: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["muster roll"]) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + musterRoll: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["works.purchase"]) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + const additionalFieldsToSet = { + projectId: applicationDetails.additionalDetails.projectId, + invoiceDate: applicationDetails.billDate, + invoiceNumber: applicationDetails.referenceId.split("_")?.[1], + contractNumber: applicationDetails.referenceId.split("_")?.[0], + documents: applicationDetails.additionalDetails.documents, + }; + return { + bill: { ...applicationDetails, ...additionalFieldsToSet }, + workflow, + }; + } + }, + enableModalSubmit: (businessService, action, setModalSubmit, data) => { + if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") { + setModalSubmit(data?.acceptTerms); + } + }, + enableHrmsSearch: (businessService, action) => { + if (businessService === businessServiceMap.estimate) { + return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); + } + if (businessService === businessServiceMap.contract) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + if (businessService === businessServiceMap?.["muster roll"]) { + return action.action.includes("VERIFY"); + } + if (businessService === businessServiceMap?.["works.purchase"]) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + return false; + }, + getBusinessService: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return businessServiceMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return businessServiceMap?.contract; + } else if (moduleCode?.includes("muster roll")) { + return businessServiceMap?.["muster roll"]; + } else if (moduleCode?.includes("works.purchase")) { + return businessServiceMap?.["works.purchase"]; + } else if (moduleCode?.includes("works.wages")) { + return businessServiceMap?.["works.wages"]; + } else if (moduleCode?.includes("works.supervision")) { + return businessServiceMap?.["works.supervision"]; + } else { + return businessServiceMap; + } + }, + getInboxModuleName: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return inboxModuleNameMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return inboxModuleNameMap?.contracts; + } else if (moduleCode?.includes("attendence")) { + return inboxModuleNameMap?.attendencemgmt; + } else { + return inboxModuleNameMap; + } + }, + SearchCampaign: { + preProcess: (data, additionalDetails) => { + const { campaignName = "", endDate = "", projectType = "", startDate = "" } = data?.state?.searchForm || {}; + data.body.CampaignDetails = {}; + data.body.CampaignDetails.pagination = data?.state?.tableForm; + data.body.CampaignDetails.tenantId = Digit.ULBService.getCurrentTenantId(); + // data.body.CampaignDetails.boundaryCode = boundaryCode; + data.body.CampaignDetails.createdBy = Digit.UserService.getUser().info.uuid; + data.body.CampaignDetails.campaignName = campaignName; + data.body.CampaignDetails.status = ["drafted"]; + if (startDate) { + data.body.CampaignDetails.startDate = Digit.Utils.date.convertDateToEpoch(startDate); + } else { + data.body.CampaignDetails.startDate = epochTimeForTomorrow12(); + } + if (endDate) { + data.body.CampaignDetails.endDate = Digit.Utils.date.convertDateToEpoch(endDate); + } + data.body.CampaignDetails.projectType = projectType?.[0]?.code; + + cleanObject(data.body.CampaignDetails); + + return data; + }, + populateProjectType: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + + return { + url: "/egov-mdms-service/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId, + moduleDetails: [ + { + moduleName: "HCM-PROJECT-TYPES", + masterDetails: [ + { + name: "projectTypes", + }, + ], + }, + ], + }, + }, + changeQueryName: "projectType", + config: { + enabled: true, + select: (data) => { + const dropdownData = filterUniqueByKey(data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes, "code").map((row) => { + return { + ...row, + i18nKey: Digit.Utils.locale.getTransformedLocale(`CAMPAIGN_TYPE_${row.code}`), + }; + }); + return dropdownData; + }, + }, + }; + }, + customValidationCheck: (data) => { + //checking if both to and from date are present then they should be startDate<=endDate + const { startDate, endDate } = data; + const startDateEpoch = Digit.Utils.date.convertDateToEpoch(startDate); + const endDateEpoch = Digit.Utils.date.convertDateToEpoch(endDate); + + if (startDate && endDate && startDateEpoch > endDateEpoch) { + return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + } + return false; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "CAMPAIGN_DATE") { + return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.endDate)}`; + } + }, + }, + SearchMicroplan: { + preProcess: (data, additionalDetails) => { + const { name, status } = data?.state?.searchForm || {}; + + data.body.PlanConfigurationSearchCriteria = {}; + data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit; + // data.body.PlanConfigurationSearchCriteria.limit = 10 + data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset; + data.body.PlanConfigurationSearchCriteria.name = name; + data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid; + // delete data.body.PlanConfigurationSearchCriteria.pagination + data.body.PlanConfigurationSearchCriteria.status = status?.status; + cleanObject(data.body.PlanConfigurationSearchCriteria); + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "CAMPAIGN_DATE") { + return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.CampaignDetails?.endDate)}`; + } + }, + }, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js new file mode 100644 index 00000000000..c9f5af95d46 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js @@ -0,0 +1,36 @@ +export const LOCALITY = "Locality"; + +export const EXCEL = "Excel"; + +export const GEOJSON = "GeoJSON"; + +export const SHAPEFILE = "Shapefile"; + +export const commonColumn = "boundaryCode"; + +export const ACCEPT_HEADERS = { + GeoJSON: "application/geo+json", + Shapefile: "application/shapefile", + Excel: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", +}; + +// Define the colors of the gradient for choropleth mapping +export const MapChoroplethGradientColors = [ + { percent: 0, color: "#edd1cf" }, + { percent: 100, color: "#b52626" }, +]; + +export const PRIMARY_THEME_COLOR = "#C84C0E"; + +export const BOUNDARY_DATA_SHEET = "MICROPLAN_BOUNDARY_DATA_SHEET"; +export const FACILITY_DATA_SHEET = "MICROPLAN_FACILITY_DATA_SHEET"; + +export const FILE_STORE = "microplan"; + +export const SHEET_PASSWORD = "eGov_sheet_password"; + +export const SHEET_COLUMN_WIDTH = 40; + +export const SCHEMA_PROPERTIES_PREFIX = "DISPLAY"; + +export const UNPROTECT_TILL_ROW = "10000"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json new file mode 100644 index 00000000000..768e323ef86 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json @@ -0,0 +1,40 @@ +{ + "timeLineOptions": [ + { + "id": 0, + "name": "MICROPLAN_DETAILS", + "component": "MicroplanDetails", + "checkForCompleteness": true + }, + { + "id": 1, + "name": "UPLOAD_DATA", + "component": "Upload", + "checkForCompleteness": true + }, + { + "id": 2, + "name": "HYPOTHESIS", + "component": "Hypothesis", + "checkForCompleteness": true + }, + { + "id": 3, + "name": "FORMULA_CONFIGURATION", + "component": "RuleEngine", + "checkForCompleteness": true + }, + { + "id": 4, + "name": "MAPPING", + "component": "Mapping", + "checkForCompleteness": false + }, + { + "id": 5, + "name": "MICROPLAN_GENERATION", + "component": "MicroplanPreview", + "checkForCompleteness": false + } + ] +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js new file mode 100644 index 00000000000..241f8ec64ec --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js @@ -0,0 +1,193 @@ +export const tourSteps = (t) => { + return { + microplanDetails: { + name: "microplanDetails", + run: true, + steps: [ + { + content: t("HELP_MICROPLAN_DETAILS_CAMPAIGN_DETAILS"), + target: ".microplan-campaign-detials", + disableBeacon: true, + placement: "bottom", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_MICROPLAN_DETAILS_MICROPLAN_NAME"), + target: ".microplan-name", + disableBeacon: true, + placement: "bottom", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + ], + tourActive: true, + }, + upload: { + name: "upload", + run: true, + steps: [ + { + content: t("HELP_UPLOAD_FILETYPE_OPTION_CONTAINER"), + target: ".upload-option-container", + disableBeacon: true, + placement: "top-end", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + ], + tourActive: true, + }, + hypothesis: { + name: "hypothesis", + run: true, + steps: [ + { + content: t("HELP_HYPOTHESIS_INTERACTABLE_SECTION"), + target: ".hypothesis-help", + disableBeacon: true, + placement: "right-start", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + // { + // content: + // t("HELP_RULE_ENGINE_INPUT"), + // target: ".last-container .key", + // disableBeacon: true, + // placement: "top-start", + // title: "", + // }, + // { + // content: + // t("HELP_HYPOTHESIS_DELETE_BUTTON"), + // target: ".last-containe .delete-button-help-locator", + // disableBeacon: true, + // placement: "top-start", + // title: "", + // }, + { + content: t("HELP_HYPOTHESIS_ADD_BUTTON"), + target: ".add-button-help", + disableBeacon: true, + placement: "top-start", + title: "", + disableOverlay :true, + }, + ], + tourActive: true, + }, + ruleEngine: { + name: "ruleEngine", + run: true, + steps: [ + { + content: t("HELP_RULE_ENGINE_INTERACTABLE_SECTION"), + target: ".rule-engine-help", + disableBeacon: true, + placement: "right-start", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_RULE_ENGINE_INPUT"), + target: ".user-input-section .interactable-section .select-and-input-wrapper-first .input", + disableBeacon: true, + placement: "top-end", + title: "", + disableOverlay :true, + }, + { + content: t("HELP_RULE_ENGINE_DELETE_BUTTON"), + target: ".select-and-input-wrapper-first .delete-button", + disableBeacon: true, + placement: "left-start", + title: "", + disableOverlay :true, + }, + { + content: t("HELP_RULE_ENGINE_ADD_BUTTON"), + target: ".add-button-help", + disableBeacon: true, + placement: "top-start", + title: "", + disableOverlay :true, + }, + ], + tourActive: true, + }, + mapping: { + name: "mapping", + run: true, + steps: [ + { + content: t("HELP_MAPPING_BOUNDARY_SELECTION"), + target: ".filter-by-boundary .button-primary", + disableBeacon: true, + placement: "right-end", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_MAPPING_BASE_MAP"), + target: ".base-map-selector .icon-first", + disableBeacon: true, + placement: "left-start", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_MAPPING_FILTER"), + target: ".filter-icon p", + disableBeacon: true, + placement: "left-start", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_MAPPING_VIRTUALIZATION"), + target: ".virtualization-icon p", + disableBeacon: true, + placement: "left-start", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_MAPPING_MAP_GEOMETRIES"), + target: ".map-container", + disableBeacon: true, + placement: "top-end", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + ], + tourActive: true, + }, + microplanPreview: { + name: "microplanPreview", + run: true, + steps: [ + { + content: t("HELP_MICROPLAN_DETAILS_EDIT_ROWS"), + target: ".preview-container", + disableBeacon: true, + placement: "top-end", + title: "", + disableOverlay :true, + disableScrolling: true, + }, + ], + tourActive: true, + }, + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js new file mode 100644 index 00000000000..1241d678738 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js @@ -0,0 +1,42 @@ +import utils from "../utils"; +import useCreatePlanConfig from "./useCreatePlanConfig"; +import useSearchPlanConfig from "./useSearchPlanConfig"; +import useUpdatePlanConfig from "./useUpdatePlanConfig"; +import useSavedMicroplans from "./useSavedMicroplans"; +import useSearchCampaign from "./useSearchCampaign"; +import { useGenerateIdCampaign } from "./useGenerateIdCampaign"; +const UserService = {}; + +const microplan = { + useCreatePlanConfig, + useSearchPlanConfig, + useUpdatePlanConfig, + useSavedMicroplans, + useSearchCampaign, + useGenerateIdCampaign, +}; + +const contracts = {}; + +const Hooks = { + attendance: { + update: () => {}, + }, + microplan, + contracts, +}; + +const Utils = { + browser: { + sample: () => {}, + }, + microplan: { + ...utils, + }, +}; + +export const CustomisedHooks = { + Hooks, + UserService, + Utils, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js new file mode 100644 index 00000000000..6afb891b15b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js @@ -0,0 +1,8 @@ +import { useMutation } from "react-query"; +import CreatePlanConfig from "../services/CreatePlanConfig"; + +const useCreatePlanConfig = () => { + return useMutation(data => CreatePlanConfig(data)) +} + +export default useCreatePlanConfig; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js new file mode 100644 index 00000000000..f315dda5ff8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js @@ -0,0 +1,26 @@ +export const useGenerateIdCampaign = ({ type, hierarchyType, filters, campaignId, config = {} }) => { + const updatedFilters = filters?.map(({ type, ...rest }) => ({ + ...rest, + boundaryType: type, + })); + const reqCriteria = { + url: `/project-factory/v1/data/_generate`, + changeQueryName: `${type}${hierarchyType}${filters}`, + params: { + tenantId: Digit.ULBService.getCurrentTenantId(), + type: type, + forceUpdate: true, + hierarchyType: hierarchyType, + campaignId: campaignId, + }, + body: type === "boundary" ? (updatedFilters === undefined ? { Filters: null } : { Filters: { boundaries: updatedFilters } }) : {}, + config: { + ...config, + cacheTime: 0, + staleTime: 0, + }, + }; + const { data: Data, refetch, isLoading } = Digit.Hooks.useCustomAPIHook(reqCriteria); + + return { isLoading: isLoading, data: Data?.GeneratedResource?.[0]?.id, refetch }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js new file mode 100644 index 00000000000..15e423d59e0 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js @@ -0,0 +1,21 @@ +import { useTranslation } from "react-i18next"; + +export const useNumberFormatter = (FormatMapping) => { + const { i18n } = useTranslation(); + + const formatNumber = (value, options) => { + try { + const currentLanguage = i18n.language; + const fallbackLanguage = i18n.options.fallbackLng[0]; // Get the first language in the fallback list + const locale = FormatMapping?.[currentLanguage] || FormatMapping?.[fallbackLanguage] || currentLanguage || ""; + return new Intl.NumberFormat(locale, options).format(value); + } catch (error) { + console.error("Error formatting number:", error); + return value; + } + }; + + return { formatNumber }; +}; + +export default useNumberFormatter; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js new file mode 100644 index 00000000000..23c1259c6c4 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js @@ -0,0 +1,23 @@ +import { useQuery } from "react-query"; +import SearchSavedPlans from "../services/searchSavedPlans"; + +const useSavedMicroplans = (reqCriteria) => { + const { body, config, params, state, url } = reqCriteria; + const { isLoading, data, isFetching, refetch } = useQuery(["SAVED_MICROPLANS", url], () => SearchSavedPlans(body), { + ...config, + cacheTime: 0, + staleTime: 0, + onError: (err) => console.error("Error fetching saved microplans:", err), + }); + + return { + isLoading, + isFetching, + data, + refetch, + revalidate: () => {}, + }; +}; + +// () => SearchSavedPlans(data) +export default useSavedMicroplans; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js new file mode 100644 index 00000000000..e2644f00ca9 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js @@ -0,0 +1,8 @@ +import { useQuery } from "react-query"; +import SearchCampaignConfig from "../services/SearchCampaignConfig"; + +const useSearchCampaign = (data, config = {}) => { + return useQuery(["SEARCH_CAMPAIGN",data], () => SearchCampaignConfig(data), { ...config }); +}; + +export default useSearchCampaign; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js new file mode 100644 index 00000000000..003fdaa4f51 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js @@ -0,0 +1,8 @@ +import { useMutation } from "react-query"; +import SearchPlanConfig from "../services/SearchPlanConfig"; + +const useSearchPlanConfig = (data, config = {}) => { + return useQuery([data?.tenantId, data?.id, data?.name, data?.executionPlanId, data?.userUuid, data?.offset, data?.limit], () => SearchPlanConfig(data), { ...config }); +}; + +export default useSearchPlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js new file mode 100644 index 00000000000..17b16145a08 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js @@ -0,0 +1,8 @@ +import { useMutation } from "react-query"; +import UpdatePlanConfig from "../services/UpdatePlanConfig"; + +const useUpdatePlanConfig = () => { + return useMutation(data => UpdatePlanConfig(data)) +} + +export default useUpdatePlanConfig; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js new file mode 100644 index 00000000000..03f82f59456 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js @@ -0,0 +1,217 @@ +import React from "react"; + +export const PopulationSvg = (style) => { + return ` + + + + + + + + + + + + `; +}; + +export const HelpOutlineIcon = ({ className = "", fill = "", style = {} }) => ( + + + + + + + + + + +); + +export const DefaultMapMarkerSvg = (style) => { + return ` + + + + + `; +}; + + +export const WarehouseMarker = ({ + className = "", + fill = "white", + fillBackground = "#42BBFF", + style = {}, + width = "3.125rem", + height = "3.125rem", +}) => { + return ` + + + + + + + + + + + + `; +}; + +export const Warehouse = ({ className = "", fill = "white", fillBackground = "#42BBFF", style = {}, width = "1.5rem", height = "1.5rem" }) => { + return ( + + + + + + + + + + + + ); +}; + +export const Church = ({ className = "", fill = "white", fillBackground = "#064466", style = {}, width = "1.5rem", height = "1.5rem" }) => { + return ( + + + + + + + + + + + + + ); +}; + +export const School = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "1.5rem", height = "1.5rem" }) => { + return ( + + + + + + + + + + + + + + + + + ); +}; + +export const HealthFacility = ({ className = "", fill = "white", fillBackground = "#0C9219", style = {}, width = "1.5rem", height = "1.5rem" , onClick=null}) => { + return ( + + + + + + + + + + + + ); +}; + +export const ChurchMarker = ({ className = "", fill = "white", fillBackground = "#064466", style = {}, width = "3.125rem", height = "3.125rem" }) => { + return ` + + + + + +`; +}; + +export const SchoolMarker = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "3.125rem", height = "3.125rem" }) => { + return ` + + + + + + + + + + + + + + + + +`; +}; + +export const HealthFacilityMarker = ({ + className = "", + fill = "white", + fillBackground = "#0C9219", + style = {}, + width = "3.125rem", + height = "3.125rem", +}) => { + return ` + + + + + + + + + + + +`; +}; + + + + + +export const PlusWithSurroundingCircle = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "1rem", height = "1rem" ,onClick=null }) => { + return ( + + + + ); +}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js new file mode 100644 index 00000000000..3885795450c --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js @@ -0,0 +1,288 @@ +import React, { useState, useEffect, useCallback, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { timeLineOptions } from "../../configs/timeLineOptions.json"; +import Upload from "../../components/Upload"; +import Hypothesis from "../../components/Hypothesis"; +import RuleEngine from "../../components/RuleEngine"; +import Mapping from "../../components/Mapping"; +import Navigator from "../../components/Nagivator"; +import { Toast } from "@egovernments/digit-ui-components"; +import MicroplanPreview from "../../components/MicroplanPreview"; +import MicroplanDetails from "../../components/MicroplanDetails"; + +export const components = { + MicroplanDetails, + Upload, + Hypothesis, + RuleEngine, + Mapping, + MicroplanPreview, +}; + +import MicroplanCreatedScreen from "../../components/MicroplanCreatedScreen"; +import { LoaderWithGap, Tutorial } from "@egovernments/digit-ui-react-components"; +import { useMyContext } from "../../utils/context"; +import { updateSessionUtils } from "../../utils/updateSessionUtils"; +import { render } from "react-dom"; + +// Main component for creating a microplan +const CreateMicroplan = () => { + // Fetching data using custom MDMS hook + const { id: campaignId = "" } = Digit.Hooks.useQueryParams(); + const { mutate: CreateMutate } = Digit.Hooks.microplan.useCreatePlanConfig(); + const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig(); + const [toRender, setToRender] = useState("navigator"); + const { t } = useTranslation(); + + // States + const [microplanData, setMicroplanData] = useState(); + const [operatorsObject, setOperatorsObject] = useState([]); + const [toast, setToast] = useState(); + const [checkForCompleteness, setCheckForCompletion] = useState([]); + const [loaderActivation, setLoaderActivation] = useState(false); + const { state } = useMyContext(); + + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + // to save microplan helper data to ssn + useEffect(() => { + if (campaignData) Digit.SessionStorage.set("microplanHelperData", { ...Digit.SessionStorage.get("microplanHelperData"), campaignData }); + }, [campaignData]); + + const campaignType = campaignData?.projectType; + + // request body for boundary hierarchy api + const reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + hierarchyType: campaignData?.hierarchyType, + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => item?.boundaryType) || {}; + }, + }, + }; + const { isLoading: ishierarchyLoading, data: hierarchyData } = Digit.Hooks.useCustomAPIHook(reqCriteria); + + // useEffect to initialise the data from MDMS + useEffect(() => { + let temp; + if (!state || !state.UIConfiguration) return; + const UIConfiguration = state?.UIConfiguration || {}; + if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); + if (!temp?.ruleConfigureOperators) return; + setOperatorsObject(temp.ruleConfigureOperators); + }, []); + + // useEffect to store data in session storage + useEffect(() => { + if (!microplanData) return; + Digit.SessionStorage.set("microplanData", microplanData); + }, [microplanData]); + + // useEffect to store data in session storage + useEffect(() => { + const data = Digit.SessionStorage.get("microplanData"); + if (data?.microplanStatus === "GENERATED") setToRender("success-screen"); + let statusData = {}; + let toCheckCompletenesData = []; + timeLineOptions.forEach((item) => { + statusData[item.name] = false; + if (item?.checkForCompleteness) toCheckCompletenesData.push(item.name); + }); + if (data && data?.status) { + if (Object.keys(data?.status) === 0) setMicroplanData({ ...data, status: statusData }); + else setMicroplanData({ ...data }); + } + setCheckForCompletion(toCheckCompletenesData); + }, []); + + // An addon function to pass to Navigator + const nextEventAddon = useCallback( + async (currentPage, checkDataCompletion, setCheckDataCompletion) => { + if (!microplanData) { + setCheckDataCompletion("perform-action"); + return; + } + setMicroplanData((previous) => ({ + ...previous, + status: { ...previous?.status, [currentPage?.name]: checkDataCompletion === "valid" }, + })); + + setCheckDataCompletion("false"); + let body = Digit.Utils.microplan.mapDataForApi( + microplanData, + operatorsObject, + microplanData?.microplanDetails?.name, + campaignId, + "DRAFT", + microplanData?.planConfigurationId ? "update" : "create" + ); + if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) { + setCheckDataCompletion("perform-action"); + return; + } + setLoaderActivation(true); + try { + if (!microplanData?.planConfigurationId) { + await createPlanConfiguration(body, setCheckDataCompletion, setLoaderActivation, state); + } else if (microplanData?.planConfigurationId) { + await updatePlanConfiguration(body, setCheckDataCompletion, setLoaderActivation, state); + } + } catch (error) { + console.error("Failed to create/update plan configuration:", error); + } + }, + [microplanData, UpdateMutate, CreateMutate] + ); + + const createPlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation, state) => { + await CreateMutate(body, { + onSuccess: async (data) => { + const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); + const additionalProps = { + hierarchyData: hierarchyData, + t, + campaignType, + campaignData, + readMeSheetName: readMeConstant ? readMeConstant.value : undefined, + }; + const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps); + if (computedSession) { + computedSession.microplanStatus = "DRAFT"; + setMicroplanData(computedSession); + } else { + console.error("Failed to compute session data."); + } + setLoaderActivation(false); + setCheckDataCompletion("perform-action"); + }, + onError: (error, variables) => { + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + transitionTime: 10000, + }); + setTimeout(() => { + setLoaderActivation(false); + setCheckDataCompletion("false"); + }, 2000); + }, + }); + }; + + const updatePlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation, state) => { + body.PlanConfiguration["id"] = microplanData?.planConfigurationId; + body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; + await UpdateMutate(body, { + onSuccess: async (data) => { + const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); + const additionalProps = { + hierarchyData: hierarchyData, + t, + campaignType, + campaignData, + readMeSheetName: readMeConstant ? readMeConstant.value : undefined, + }; + const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps); + if (computedSession) { + computedSession.microplanStatus = "DRAFT"; + setMicroplanData(computedSession); + } else { + console.error("Failed to compute session data."); + } + setLoaderActivation(false); + setCheckDataCompletion("perform-action"); + }, + onError: (error, variables) => { + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + transitionTime: 10000, + }); + setTimeout(() => { + setLoaderActivation(false); + setCheckDataCompletion("false"); + }, 2000); + }, + }); + }; + + const setCurrentPageExternally = useCallback( + (props) => { + switch (props.method) { + case "set": { + let currentPage; + const data = Digit.SessionStorage.get("microplanData"); + if (data?.currentPage) currentPage = data.currentPage; + if (currentPage && props?.setCurrentPage && timeLineOptions.find((item) => item.id === currentPage?.id)) { + props.setCurrentPage(currentPage); + return true; + } + break; + } + case "save": { + if (props.currentPage) { + setMicroplanData((previous) => ({ ...previous, currentPage: props.currentPage })); + } + break; + } + } + }, + [microplanData, setMicroplanData, Navigator] + ); + + const completeNavigation = useCallback(() => { + setToRender("success-screen"); + }, [setToRender]); + + return ( + <> +
+ {toRender === "navigator" && ( + + )} + {toRender === "success-screen" && } +
+ {toast && ( + setToast(undefined)} + /> + )} + {loaderActivation && } + + ); +}; + +export default CreateMicroplan; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js new file mode 100644 index 00000000000..7534c1b2af1 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js @@ -0,0 +1,54 @@ +import React, { Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { Link } from "react-router-dom"; +import { ArrowForward } from "@egovernments/digit-ui-svg-components"; +import { Button } from "@egovernments/digit-ui-react-components"; +import { useHistory } from "react-router-dom"; +import { ActionBar } from "@egovernments/digit-ui-components"; + +const Guidelines = ({ path }) => { + const { t } = useTranslation(); + const history = useHistory() + // Keeping inline style for now because design for this screen is not given yet + const { id = "" } = Digit.Hooks.useQueryParams(); + const onNextClick = ()=>{ + history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${id}`); + } + return ( + <> + +
+ {t("CREATE_MICROPLAN_GUIDELINES")} +
+ + {/* Action bar */} + + {/* Next/Submit button */} + + + + ); +}; + +export default Guidelines; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js new file mode 100644 index 00000000000..bbb0aef7628 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js @@ -0,0 +1,200 @@ +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Header, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components"; +import { useHistory } from "react-router-dom"; +import { updateSessionUtils } from "../../utils/updateSessionUtils"; +import { useMyContext } from "../../utils/context"; + +const configs = { + label: "SAVED_MICROPLANS", + type: "search", + apiDetails: { + serviceName: "/plan-service/config/_search", + requestParam: {}, + requestBody: {}, + minParametersForSearchForm: 0, + masterName: "commonUiConfig", + moduleName: "SearchMicroplan", + tableFormJsonPath: "requestBody.PlanConfigurationSearchCriteria.pagination", + searchFormJsonPath: "requestBody.PlanConfigurationSearchCriteria", + }, + sections: { + search: { + uiConfig: { + type: "search", + typeMobile: "filter", + headerLabel: "SAVED_MICROPLANS", + headerStyle: null, + primaryLabel: "ES_COMMON_SEARCH", + secondaryLabel: "ES_COMMON_CLEAR_SEARCH", + minReqFields: 0, + // "showFormInstruction": "TQM_SEARCH_HINT", + defaultValues: { + name: "", + status: "", + }, + fields: [ + { + label: "MICROPLAN_NAME", + type: "text", + isMandatory: false, + disable: false, + populators: { + name: "name", + style: { + marginBottom: "0px", + }, + }, + }, + { + label: "MICROPLAN_STATUS", + type: "dropdown", + isMandatory: false, + disable: false, + populators: { + name: "status", + optionsKey: "status", + optionsCustomStyle: { + top: "2.3rem", + }, + mdmsConfig: { + masterName: "MicroplanStatus", + moduleName: "hcm-microplanning", + localePrefix: "MICROPLAN_STATUS", + }, + }, + }, + ], + }, + label: "", + children: {}, + show: true, + // "labelMobile": "TQM_INBOX_SEARCH" + }, + searchResult: { + uiConfig: { + columns: [ + { + label: "MICROPLAN_NAME", + jsonPath: "name", + }, + { + label: "MICROPLAN_STATUS", + jsonPath: "status", + prefix: "MICROPLAN_STATUS_COLUMN_", + translate: true, + }, + { + label: "CAMPAIGNS_ASSIGNED", + jsonPath: "CampaignDetails.campaignName", + }, + { + label: "CAMPAIGN_DATE", + jsonPath: "CampaignDetails.startDate", + additionalCustomization: true, + }, + ], + showActionBarMobileCard: true, + actionButtonLabelMobileCard: "TQM_VIEW_RESULTS", + enableGlobalSearch: false, + enableColumnSort: true, + resultsJsonPath: "PlanConfiguration", + tableClassName: "table pqm-table", + noColumnBorder: true, + rowClassName: "table-row-mdms table-row-mdms-hover", + }, + children: {}, + show: true, + }, + }, + additionalSections: {}, + persistFormData: true, + showAsRemovableTagsInMobile: false, + customHookName: "microplan.useSavedMicroplans", +}; + +const SavedMicroplans = () => { + const [showLoader, setShowLoader] = useState(false); + const { state } = useMyContext(); + const history = useHistory(); + const { t } = useTranslation(); + + const fetchHierarchyData = async (hierarchyType) => { + const response = await Digit.CustomService.getResponse({ + url: "/boundary-service/boundary-hierarchy-definition/_search", + useCache: false, + method: "POST", + userService: false, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + hierarchyType, + }, + }, + }); + if (response?.BoundaryHierarchy?.length) { + return response.BoundaryHierarchy[0].boundaryHierarchy.map((item) => item.boundaryType); + } + console.error("Invalid response structure"); + }; + + const computeAdditionalProps = (row, state, t, hierarchyData) => { + const campaignDetails = row?.original?.CampaignDetails; + const readMeSheetName = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value; + return { + hierarchyData, + t, + campaignType: campaignDetails?.projectType, + campaignData: campaignDetails, + readMeSheetName, + }; + }; + + const onClickRow = (row) => { + const handleClick = async () => { + setShowLoader(true); + try { + const campaignType = row?.original?.CampaignDetails?.projectType; + const hierarchyData = await fetchHierarchyData(row?.original?.CampaignDetails?.hierarchyType); + const additionalProps = computeAdditionalProps(row, state, t, hierarchyData); + + // Compute the session object based on the row?.original data and then re-route + const computedSession = await updateSessionUtils.computeSessionObject(row.original, state, additionalProps); + Digit.SessionStorage.set("microplanData", computedSession); + + setShowLoader(false); + history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.executionPlanId}`); + } catch (error) { + console.error(`Failed to process the request: ${error.message}`); + setShowLoader(false); + } + }; + + handleClick(); + }; + + const savedMircoplanSession = Digit.Hooks.useSessionStorage("SAVED_MICROPLAN_SESSION", {}); + + if (showLoader) { + return ; + } + + return ( + +
{t(configs?.label)}
+
+ +
+
+ ); +}; + +export default SavedMicroplans; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js new file mode 100644 index 00000000000..8f2131eefdd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js @@ -0,0 +1,226 @@ +import React, { useEffect, useMemo } from "react"; +import { useTranslation } from "react-i18next"; +import { Header, InboxSearchComposer, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components"; +import { useHistory, useParams } from "react-router-dom"; + +const configs = { + label: "SELECT_CAMPAIGN", + type: "search", + apiDetails: { + serviceName: "/project-factory/v1/project-type/search", + requestParam: {}, + requestBody: {}, + minParametersForSearchForm: 0, + masterName: "commonUiConfig", + moduleName: "SearchCampaign", + tableFormJsonPath: "requestBody.CampaignDetails.pagination", + searchFormJsonPath: "requestBody.CampaignDetails", + }, + sections: { + search: { + uiConfig: { + type: "search", + // typeMobile: "filter", + headerLabel: "SELECT_CAMPAIGN", + headerStyle: null, + primaryLabel: "ES_COMMON_SEARCH", + secondaryLabel: "ES_COMMON_CLEAR_SEARCH", + minReqFields: 1, + // "showFormInstruction": "TQM_SEARCH_HINT", + defaultValues: { + campaignName: "", + projectType: "", + startDate: "", + endDate: "", + boundaryCode: "", + }, + fields: [ + { + label: "CAMPAIGN_NAME", + type: "text", + isMandatory: false, + disable: false, + populators: { + name: "campaignName", + style: { + marginBottom: "0px", + }, + error: "ERR_MIN_LENGTH_CAMPAIGN_NAME", + validationErrorStyles: { + marginTop: "0.3rem", + }, + validation: { + minLength: 2, + }, + }, + }, + // { + // label: "CAMPAIGN_TYPE", + // type: "dropdown", + // isMandatory: false, + // disable: false, + // populators: { + // name: "projectType", + // optionsKey: "name", + // optionsCustomStyle: { + // top: "2.3rem", + // }, + // mdmsConfig: { + // masterName: "projectTypes", + // moduleName: "HCM-PROJECT-TYPES", + // localePrefix: "CAMPAIGN_TYPE", + // }, + // }, + // }, + { + label: "CAMPAIGN_TYPE", + type: "apidropdown", + isMandatory: false, + disable: false, + populators: { + name: "projectType", + optionsKey: "i18nKey", + optionsCustomStyle: { + top: "2.3rem", + }, + allowMultiSelect: false, + masterName: "commonUiConfig", + moduleName: "SearchCampaign", + customfn: "populateProjectType", + }, + }, + { + label: "CAMPAIGN_START_DATE", + type: "date", + isMandatory: false, + key: "startDate", + disable: false, + preProcess: { + updateDependent: ["populators.max"], + }, + populators: { + name: "startDate", + style: { + marginBottom: "0px", + }, + error: "DATE_VALIDATION_MSG", + }, + }, + { + label: "CAMPAIGN_END_DATE", + type: "date", + isMandatory: false, + disable: false, + key: "endDate", + preProcess: { + updateDependent: ["populators.max"], + }, + populators: { + name: "endDate", + error: "DATE_VALIDATION_MSG", + min: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString().slice(0, 10), + style: { + marginBottom: "0px", + }, + }, + }, + // { + // label: "CAMPAIGN_BOUNDARY", + // type: "text", + // isMandatory: false, + // disable: false, + // populators: { + // name: "boundaryCode", + // style: { + // marginBottom: "0px", + // }, + // }, + // }, + ], + }, + label: "", + children: {}, + show: true, + // "labelMobile": "TQM_INBOX_SEARCH" + }, + searchResult: { + uiConfig: { + columns: [ + { + label: "CAMPAIGN_NAME", + jsonPath: "campaignName", + // "additionalCustomization": true + }, + { + label: "CAMPAIGN_TYPE", + jsonPath: "projectType", + // "additionalCustomization": false, + prefix: "CAMPAIGN_TYPE_", + translate: true, + }, + { + label: "CAMPAIGN_BOUNDARY_CAMP", + jsonPath: "boundaryCode", + // "additionalCustomization": false, + prefix: "CAMPAIGN_BOUNDARY_", + translate: true, + }, + { + label: "CAMPAIGN_BENEFICIARY_TYPE", + jsonPath: "additionalDetails.beneficiaryType", + prefix: "CAMPAIGN_BENEFICIARY_TYPE_", + translate: true, + }, + { + label: "CAMPAIGN_DATE", + jsonPath: "startDate", + additionalCustomization: true, + }, + ], + showActionBarMobileCard: true, + actionButtonLabelMobileCard: "TQM_VIEW_RESULTS", + enableGlobalSearch: false, + enableColumnSort: true, + resultsJsonPath: "CampaignDetails", + tableClassName: "table pqm-table", + rowClassName: "table-row-mdms table-row-mdms-hover", + noColumnBorder: true, + }, + children: {}, + show: true, + }, + }, + additionalSections: {}, + persistFormData: true, + showAsRemovableTagsInMobile: false, +}; +const SelectCampaign = () => { + const { t } = useTranslation(); + const history = useHistory(); + + const onClickRow = (row) => { + // history.push(`/${window.contextPath}/employee/microplanning/help-guidelines?id=${row?.original?.id}`); + history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.id}`); + }; + + const SelectCampaignSession = Digit.Hooks.useSessionStorage("SELECT_CAMPAIGN_SESSION", {}); + + return ( + +
{t(configs?.label)}
+
+ +
+
+ ); +}; + +export default SelectCampaign; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js new file mode 100644 index 00000000000..6f58779637a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js @@ -0,0 +1,128 @@ +import React, { useEffect } from "react"; +import { Switch, useLocation } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { PrivateRoute, AppContainer, BreadCrumb, Loader } from "@egovernments/digit-ui-react-components"; +import MicroplanningHeader from "../../components/MicroplanningHeader"; +import Guidelines from "./Guidelines"; +import CreateMicroplan from "./CreateMicroplan"; +import SavedMicroplans from "./SavedMicroplans"; +import SelectCampaign from "./SelectCampaign"; +import { useMyContext } from "../../utils/context"; + +const MicroplanningBreadCrumb = ({ location, defaultPath }) => { + const { t } = useTranslation(); + const pathVar = location.pathname.replace(`${defaultPath}/`, "").split("?")?.[0]; + const { masterName, moduleName, uniqueIdentifier } = Digit.Hooks.useQueryParams(); + + const crumbs = [ + { + path: `/${window?.contextPath}/employee`, + content: t("Home"), + show: true, + }, + // { + // content: t(`UPLOAD`) , + // show: pathVar.includes("upload")?true: false, + // }, + // { + // content: t(`HYPOTHESIS`) , + // show: pathVar.includes("hypothesis")?true: false, + // }, + // { + // content: t(`RULE_ENGINE`) , + // show: pathVar.includes("rule-engine")?true: false, + // }, + { + content: t(`CREATE_MICROPLAN`), + show: pathVar.includes("create-microplan"), + }, + { + content: t(`SAVED_MICROPLANS_TEXT`), + show: pathVar.includes("saved-microplan"), + }, + { + content: t(`CREATE_MICROPLAN`), + show: pathVar.includes("select-campaign"), + }, + ]; + return ; +}; + +const App = ({ path }) => { + const { dispatch } = useMyContext(); + + const location = useLocation(); + const MDMSCreateSession = Digit.Hooks.useSessionStorage("MDMS_add", {}); + const [sessionFormData, setSessionFormData, clearSessionFormData] = MDMSCreateSession; + + const MDMSViewSession = Digit.Hooks.useSessionStorage("MDMS_view", {}); + const [sessionFormDataView, setSessionFormDataView, clearSessionFormDataView] = MDMSViewSession; + + const { isLoading: isLoadingMdmsBaseData, data } = Digit.Hooks.useCustomMDMS( + Digit.ULBService.getCurrentTenantId(), + "hcm-microplanning", + [ + { name: "UploadConfiguration" }, + { name: "UIConfiguration" }, + { name: "Schemas" }, + { name: "RuleConfigureOutput" }, + { name: "Resources" }, + { name: "HypothesisAssumptions" }, + { name: "BaseMapLayers" }, + { name: "MicroplanPreviewAggregates" }, + { name: "AutoFilledRuleConfigurations" }, + { name: "MapFilters" }, + { name: "HierarchyConfigurations" }, + { name: "NumberFormatMappingForTranslation" }, + { name: "UploadGuidelines" }, + { name: "ReadMeData" }, + { name: "CommonConstants" }, + ], + { + select: (data) => { + dispatch({ + type: "SETINITDATA", + state: { + ...data?.["hcm-microplanning"], + }, + }); + }, + } + ); + + //destroying session + useEffect(() => { + const pathVar = location.pathname.replace(`${path}/`, "").split("?")?.[0]; + Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan"], "microplanData"); + Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan"], "microplanHelperData"); + Digit.Utils.microplan.destroySessionHelper(pathVar, ["select-campaign"], "SELECT_CAMPAIGN_SESSION"); + Digit.Utils.microplan.destroySessionHelper(pathVar, ["saved-microplans"], "SAVED_MICROPLAN_SESSION"); + }, [location]); + + if (isLoadingMdmsBaseData) { + return ; + } + + return ( + +
+ + +
+ + + {/* } /> + } /> + } /> */} + } /> + + } /> + } /> + } /> + + +
+ ); +}; + +export default App; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js new file mode 100644 index 00000000000..cabc9b67b56 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js @@ -0,0 +1,19 @@ +const CreatePlanConfig = async (body) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/plan-service/config/_create", + useCache: false, + method: "POST", + userService: true, + body, + }); + return response; + } catch (error) { + if (error?.response?.data?.Errors) { + throw new Error(error.response.data.Errors[0].message); + } + throw new Error("An unknown error occurred"); + } +}; + +export default CreatePlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js new file mode 100644 index 00000000000..83d4fb5fc72 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js @@ -0,0 +1,181 @@ +import _ from "lodash"; + +const createProjectsArray = (t, project, searchParams, headerLocale) => { + let totalProjects = { + searchedProject: {}, + subProjects: [], + }; + let basicDetails = {}; + let totalProjectsLength = project.length; + // for(let projectIndex = 0; projectIndex < totalProjectsLength; projectIndex++) { + let currentProject = project[0]; + const headerDetails = { + title: " ", + asSectionHeader: true, + values: [ + { title: "WORKS_PROJECT_ID", value: currentProject?.projectNumber || "NA" }, + { title: "ES_COMMON_PROPOSAL_DATE", value: Digit.Utils.pt.convertEpochToDate(currentProject?.additionalDetails?.dateOfProposal) || "NA" }, + { title: "WORKS_PROJECT_NAME", value: currentProject?.name || "NA" }, + { title: "PROJECT_PROJECT_DESC", value: currentProject?.description || "NA" }, + ], + }; + + const projectDetails = { + title: "WORKS_PROJECT_DETAILS", + asSectionHeader: true, + values: [ + { title: "PROJECT_LOR", value: currentProject?.referenceID || "NA" }, + { + title: "WORKS_PROJECT_TYPE", + value: currentProject?.projectType ? t(`COMMON_MASTERS_${Digit.Utils.locale.getTransformedLocale(currentProject?.projectType)}`) : "NA", + }, + { + title: "PROJECT_TARGET_DEMOGRAPHY", + value: currentProject?.additionalDetails?.targetDemography + ? t(`COMMON_MASTERS_${currentProject?.additionalDetails?.targetDemography}`) + : "NA", + }, + { + title: "PROJECT_ESTIMATED_COST", + value: currentProject?.additionalDetails?.estimatedCostInRs + ? `₹ ${Digit.Utils.dss.formatterWithoutRound(currentProject?.additionalDetails?.estimatedCostInRs, "number")}` + : "NA", + }, + ], + }; + + const locationDetails = { + title: "WORKS_LOCATION_DETAILS", + asSectionHeader: true, + values: [ + { + title: "WORKS_GEO_LOCATION", + value: + currentProject?.address?.latitude || currentProject?.address?.longitude + ? `${currentProject?.address?.latitude}, ${currentProject?.address?.longitude}` + : "NA", + }, + { + title: "WORKS_CITY", + value: currentProject?.address?.city ? t(`TENANT_TENANTS_${Digit.Utils.locale.getTransformedLocale(currentProject?.address?.city)}`) : "NA", + }, //will check with Backend + { title: "WORKS_WARD", value: currentProject?.address?.boundary ? t(`${headerLocale}_ADMIN_${currentProject?.address?.boundary}`) : "NA" }, ///backend to update this + { + title: "WORKS_LOCALITY", + value: currentProject?.additionalDetails?.locality ? t(`${headerLocale}_ADMIN_${currentProject?.additionalDetails?.locality}`) : "NA", + }, + ], + }; + + // const financialDetails = { + // title: "WORKS_FINANCIAL_DETAILS", + // asSectionHeader: false, + // values: [ + // { title: "WORKS_HEAD_OF_ACCOUNTS", value: currentProject?.additionalDetails?.fund ? t(`COMMON_MASTERS_FUND_${currentProject?.additionalDetails?.fund}`) : "NA" }, + // ], + // }; + + let documentDetails = { + title: "", + asSectionHeader: true, + additionalDetails: { + documents: [ + { + title: "WORKS_RELEVANT_DOCUMENTS", + BS: "Works", + values: currentProject?.documents?.map((document) => { + if (document?.status !== "INACTIVE") { + return { + title: document?.documentType === "OTHERS" ? document?.additionalDetails?.otherCategoryName : t(`PROJECT_${document?.documentType}`), + documentType: document?.documentType, + documentUid: document?.fileStore, + fileStoreId: document?.fileStore, + }; + } + return {}; + }), + }, + ], + }, + }; + + //filter any empty object + documentDetails.additionalDetails.documents[0].values = documentDetails?.additionalDetails?.documents?.[0]?.values?.filter((value) => { + if (value?.title) { + return value; + } + }); + + // if(currentProject?.projectNumber === searchParams?.Projects?.[0]?.projectNumber) { + basicDetails = { + projectID: currentProject?.projectNumber, + projectProposalDate: Digit.Utils.pt.convertEpochToDate(currentProject?.additionalDetails?.dateOfProposal) || "NA", + projectName: currentProject?.name || "NA", + projectDesc: currentProject?.description || "NA", + projectHasSubProject: totalProjectsLength > 1 ? "COMMON_YES" : "COMMON_NO", + projectParentProjectID: currentProject?.ancestors?.[0]?.projectNumber || "NA", + uuid: currentProject?.id, + address: currentProject?.address, + ward: currentProject?.address?.boundary, + locality: currentProject?.additionalDetails?.locality, + }; + totalProjects.searchedProject = { + basicDetails, + headerDetails, + projectDetails, + locationDetails, + documentDetails, + }; + // } + // } + return totalProjects; +}; + +export const Search = { + viewProjectDetailsScreen: async ( + t, + tenantId, + searchParams, + filters = { limit: 10, offset: 0, includeAncestors: true, includeDescendants: true }, + headerLocale + ) => { + const response = await Digit.WorksService?.searchProject(tenantId, searchParams, filters); + + let projectDetails = { + searchedProject: { + basicDetails: {}, + details: { + projectDetails: [], + }, + }, + }; + + if (response?.Project) { + let projects = createProjectsArray(t, response?.Project, searchParams, headerLocale); + + //searched Project details + projectDetails.searchedProject["basicDetails"] = projects?.searchedProject?.basicDetails; + projectDetails.searchedProject["details"]["projectDetails"] = { + applicationDetails: [ + projects?.searchedProject?.headerDetails, + projects?.searchedProject?.projectDetails, + projects?.searchedProject?.locationDetails, + projects?.searchedProject?.documentDetails, + ], + }; //rest categories will come here + } + + return { + projectDetails: response?.Project ? projectDetails : [], + response: response?.Project, + processInstancesDetails: [], + workflowDetails: [], + applicationData: {}, + isNoDataFound: response?.Project?.length === 0, + }; + }, + searchEstimate: async (tenantId, filters) => { + const response = await Digit.WorksService?.estimateSearch({ tenantId, filters }); + return response?.estimates; + }, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js new file mode 100644 index 00000000000..bb6a9f26916 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js @@ -0,0 +1,22 @@ +const SearchCampaignConfig = async (body) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/project-factory/v1/project-type/search", + useCache: false, + method: "POST", + userService: false, + body, + }); + if (response?.CampaignDetails?.length === 0) { + throw new Error("Campaign not found with the given id"); + } + return response?.CampaignDetails?.[0]; + } catch (error) { + if (error?.response?.data?.Errors) { + throw new Error(error.response.data.Errors[0].message); + } + throw new Error("An unknown error occurred"); + } +}; + +export default SearchCampaignConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js new file mode 100644 index 00000000000..1fe11f206a7 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js @@ -0,0 +1,19 @@ +const SearchPlanConfig = async (body) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/plan-service/config/_search", + useCache: false, + method: "POST", + userService: true, + body, + }); + return response; + } catch (error) { + if (error?.response?.data?.Errors) { + throw new Error(error.response.data.Errors[0].message); + } + throw new Error("An unknown error occurred"); + } +}; + +export default SearchPlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js new file mode 100644 index 00000000000..d1623cbd167 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js @@ -0,0 +1,18 @@ +const UpdatePlanConfig = async (body) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/plan-service/config/_update", + useCache: false, + method: "POST", + userService: true, + body, + }); + return response; + } catch (error) { + if (error?.response?.data?.Errors) { + throw new Error(error.response.data.Errors[0].message); + } + throw new Error("An unknown error occurred"); + } +}; +export default UpdatePlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js new file mode 100644 index 00000000000..ba4342526a8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js @@ -0,0 +1,67 @@ +function mergeArrays(array1, key1, array2, key2) { + const mergedArray = []; + + // Create a map of values from array2 using key2 + const map = new Map(); + array2.forEach((item) => { + map.set(item[key2], item); + }); + + // Iterate over array1 and merge with matching items from array2 + array1.forEach((item) => { + const matchingItem = map.get(item[key1]); + if (matchingItem) { + // Merge properties from both items and append to 'CampaignDetails' + const mergedItem = { ...item, CampaignDetails: { ...matchingItem } }; + mergedArray.push(mergedItem); + } else { + // No matching item found in array2, add array1 item with empty 'CampaignDetails' + const mergedItem = { ...item, CampaignDetails: {} }; + mergedArray.push(mergedItem); + } + }); + return mergedArray; +} + +const SearchSavedPlans = async (body) => { + try { + //here get response from both apis and process data and return + const responsePlan = await Digit.CustomService.getResponse({ + url: "/plan-service/config/_search", + useCache: false, + method: "POST", + userService: false, + body, + }); + + const { PlanConfiguration } = responsePlan; + if (!PlanConfiguration || PlanConfiguration.length === 0) return []; + + const executionPlanIds = PlanConfiguration?.map((row) => row?.executionPlanId)?.filter((item) => item); + const CampaignDetails = { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: executionPlanIds, + }; + + const responseCampaign = await Digit.CustomService.getResponse({ + url: "/project-factory/v1/project-type/search", + useCache: false, + method: "POST", + userService: false, + body: { + CampaignDetails, + }, + }); + const finalResult = { + PlanConfiguration: mergeArrays(responsePlan?.PlanConfiguration, "executionPlanId", responseCampaign?.CampaignDetails, "id"), + }; + return finalResult; + } catch (error) { + if (error?.response?.data?.Errors) { + throw new Error(error.response.data.Errors[0].message); + } + throw new Error("An unknown error occurred"); + } +}; + +export default SearchSavedPlans; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js new file mode 100644 index 00000000000..5e6c18f699e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js @@ -0,0 +1,31 @@ +import React,{useContext,createContext,useReducer} from "react" + +const MyContext = createContext() +const initialState = { + +} + +const reducer = (state=initialState,action) => { + switch (action.type) { + case "SETINITDATA": + return {...state,...action.state} + default: + return state; + } +} + +export const useMyContext = () => { + + return useContext(MyContext) +} + +export const ProviderContext = ({children}) => { + + const [state,dispatch] = useReducer(reducer,initialState) + + return ( + + {children} + + ) +} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js new file mode 100644 index 00000000000..a3f79c2358e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js @@ -0,0 +1,485 @@ +import { BOUNDARY_DATA_SHEET, FACILITY_DATA_SHEET, SCHEMA_PROPERTIES_PREFIX, commonColumn } from "../configs/constants"; + +export const fetchBoundaryData = async (tenantId, hierarchyType, codes) => { + // request for boundary relation api + const reqCriteria = { + url: "/boundary-service/boundary-relationships/_search", + params: { tenantId, hierarchyType, codes, includeChildren: true }, + body: {}, + }; + let response; + try { + response = (await Digit.CustomService.getResponse(reqCriteria))?.TenantBoundary?.[0]?.boundary || {}; + } catch (error) { + console.error("Error in fetching boundary Data: ", error.message); + } + return response; +}; + +export const getFacilities = async (params, body) => { + // request for boundary relation api + const reqCriteria = { + url: "/facility/v1/_search", + params: params, + body: body, + }; + let response; + try { + response = (await Digit.CustomService.getResponse(reqCriteria))?.Facilities || {}; + } catch (error) { + if (error.response) { + throw new Error(`Failed to fetch facility data: ${error.response.data.message}`); + } + if (error.request) { + // Network error + throw new Error("Network error while fetching facility data"); + } + // Other errors + throw new Error(`Error while fetching facility data: ${error.message}`); + } + return response; +}; + +// export const fetchColumnsFromMdms = (schema)=>{ +// return +// } + +/** + * + * @param {*} xlsxData + * @param {*} boundaryData + * @returns xlsxData with boundary data added + */ +export const addBoundaryData = (xlsxData, boundaryData, hierarchyType) => { + // Return the original data if there is no boundary data to add + if (!boundaryData) return xlsxData; + + // Initialize the array to hold new data + let newXlsxData = []; + + // Recursive function to convert boundary data into sheet format + const convertBoundaryDataToSheets = (boundaryData, currentBoundaryPredecessor = [], hierarchyAccumulator = [], dataAccumulator = []) => { + // Return if boundary data is not valid or not an array + if (!boundaryData || !Array.isArray(boundaryData)) return; + + // Clone the current boundary predecessor to avoid modifying the original data + const rowData = [...currentBoundaryPredecessor]; + // Clone the data accumulator to preserve the accumulated data + let tempDataAccumulator = [...dataAccumulator]; + // Use a set to accumulate unique hierarchy levels + let tempHierarchyAccumulator = new Set(hierarchyAccumulator); + + // Iterate over each item in the boundary data array + for (const item of boundaryData) { + if (item?.code) { + // Create a new row with the current item's code + const tempRow = [...rowData, item?.code]; + let response; + // Add the current item's boundary type to the hierarchy + tempHierarchyAccumulator.add(item.boundaryType); + + // If the current item has children, recursively process them + if (item.children) + response = convertBoundaryDataToSheets(item.children, tempRow, tempHierarchyAccumulator, [...tempDataAccumulator, tempRow]); + + // Update the accumulators with the response from the recursive call + if (response) { + tempDataAccumulator = response.tempDataAccumulator; + tempHierarchyAccumulator = response.tempHierarchyAccumulator; + } + } + } + + // Return the accumulated data and hierarchy + return { tempDataAccumulator, tempHierarchyAccumulator }; + }; + + // Convert the boundary data into sheet format and extract the sorted data and hierarchy + let { tempDataAccumulator: sortedBoundaryDataForXlsxSheet, tempHierarchyAccumulator: hierarchy } = convertBoundaryDataToSheets(boundaryData); + + // Add the hierarchy as the first row of the sheet + hierarchy = [...hierarchy].map((item) => `${hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`); + sortedBoundaryDataForXlsxSheet = [[...hierarchy], ...sortedBoundaryDataForXlsxSheet]; + + // Determine the maximum row length to ensure all rows have the same length + const topIndex = Math.max(...sortedBoundaryDataForXlsxSheet.map((row) => row.length)) - 1; + + // Ensure all rows are of the same length by filling them with empty strings + sortedBoundaryDataForXlsxSheet = sortedBoundaryDataForXlsxSheet.map((item, index) => { + let newItem = item; + if (index !== 0) { + if (!newItem) { + newItem = []; + } + const itemLength = newItem.length; + while (newItem.length <= topIndex) { + newItem.push(""); + } + newItem.push(newItem[itemLength - 1]); + } else { + newItem.push(commonColumn); + } + + return newItem; + }); + + // Add the new sheet data to the original data + newXlsxData = [...xlsxData, ...newXlsxData, { sheetName: BOUNDARY_DATA_SHEET, data: sortedBoundaryDataForXlsxSheet }]; + + // Return the updated data + return newXlsxData; +}; + +const fillDataWithBlanks = (data, tillRow) => { + while (data.length < tillRow) { + data.push([]); + } + + const maxLength = Math.max(...data.map((row) => row.length)); + return data.map((row) => [...row, ...new Array(maxLength - row.length).fill("")]); +}; +const generateLocalisationKeyForSchemaProperties = (code) => { + if (!code) return code; + return `${SCHEMA_PROPERTIES_PREFIX}_${code}`; +}; +/** + * + * @param {array} xlsxData , xlsx data + * @param {object} schema , schema to refer to + * @returns {Array of Object} , xlsxData with schema data added + * + * adds schema data to sheets + */ +const addSchemaData = (xlsxData, schema, extraColumnsToAdd) => { + if (!schema) return xlsxData; + let columnSchema = schema.schema?.Properties || {}; + const newXlsxData = []; + const columnList = [[], [], [], []]; // Initialize columnList with four empty arrays + + for (const [key, value] of Object.entries(columnSchema)) { + if (key === commonColumn) continue; + + columnList[0].push(generateLocalisationKeyForSchemaProperties(key)); // Add key to the first array + + // columnList[1].push(value.type || ""); // Add type to the second array + + // columnList[2].push(value.isRequired ? "MANDATORY" : "OPTIONAL"); // Add requirement status to the third array + + // columnList[3].push(value.pattern || ""); // Add pattern to the fourth array + } + + if (extraColumnsToAdd) columnList[0].push(...extraColumnsToAdd); + + for (let { sheetName, data } of xlsxData) { + data = fillDataWithBlanks(data, 4); + columnList.forEach((item, index) => { + // Append the new items to the row + if (data[index]) { + data[index] = [...data[index], ...item]; + } else { + data[index] = [...item]; + } + }); + + newXlsxData.push({ sheetName, data }); + } + + return newXlsxData; +}; + +/** + * + * @param {Array of Object} xlsxData + * @param {string} hierarchyLevelName + */ +const devideXlsxDataHierarchyLevelWise = (xlsxData, hierarchyLevelName) => { + if (!hierarchyLevelName) return xlsxData; // Return original data if no hierarchy level name + + const result = []; // Initialize result array + + // Iterate over each sheet in the xlsxData + for (const sheet of xlsxData) { + const sheetData = sheet.data; + const hierarchyLevelIndex = sheetData[0].indexOf(hierarchyLevelName); + + // If hierarchy level name not found, skip this sheet + if (hierarchyLevelIndex === -1) { + result.push(sheet); + continue; + } + + const { sheetsMap, danglingDataMap } = processSheetData(sheetData, hierarchyLevelIndex); + + // Combine danglingDataMap with sheetsMap + for (const key of Object.keys(danglingDataMap)) { + if (sheetsMap[key]) { + sheetsMap[key].data = [sheetData[0], ...danglingDataMap[key], ...sheetsMap[key].data.slice(1)]; + } else { + sheetsMap[key] = { + sheetName: key, + data: [...danglingDataMap[key], sheetData[0]], + }; + } + } + + // Add sheetsMap values to result + result.push(...Object.values(sheetsMap)); + } + + return result.length > 0 ? result : xlsxData; // Return result or original data if result is empty +}; + +// Function to process sheet data and return sheetsMap and danglingDataMap +const processSheetData = (sheetData, hierarchyLevelIndex) => { + const sheetsMap = {}; + const danglingDataMap = {}; + let emptyHierarchyRow = []; + let lastWasEmpty = true; + + // Iterate through sheet data starting from the second row (skipping header) + for (let i = 1; i < sheetData.length; i++) { + const row = sheetData[i]; + const hierarchyValue = row[hierarchyLevelIndex]; + + if (emptyHierarchyRow.length && hierarchyValue !== "") { + danglingDataMap[hierarchyValue] = emptyHierarchyRow; + } + + if (hierarchyValue === "" && lastWasEmpty) { + emptyHierarchyRow.push(row); + } else { + emptyHierarchyRow = []; + } + + if (!sheetsMap[hierarchyValue] && hierarchyValue !== "") { + sheetsMap[hierarchyValue] = { + sheetName: hierarchyValue, + data: [sheetData[0]], + }; + } + + if (hierarchyValue === row[hierarchyLevelIndex] && hierarchyValue !== "") { + sheetsMap[hierarchyValue].data.push(row); + } + + lastWasEmpty = hierarchyValue === ""; + } + + return { sheetsMap, danglingDataMap }; +}; + +export const filterBoundaries = (boundaryData, boundaryFilters) => { + if (!boundaryFilters) return boundaryData; + // Define a helper function to recursively filter boundaries + function filterRecursive(boundary) { + // Find the filter that matches the current boundary + const filter = boundaryFilters?.find((f) => f.code === boundary.code && f.type === boundary.boundaryType); + + // If no filter is found, return the boundary with its children filtered recursively + if (!filter) { + return { + ...boundary, + children: boundary.children.map(filterRecursive), + }; + } + + // If the boundary has no children, handle the case where includeAllChildren is false + if (!boundary.children.length) { + // Return the boundary with an empty children array + return { + ...boundary, + children: [], + }; + } + + // If includeAllChildren is true, return the boundary with all children + if (filter.includeAllChildren) { + return { + ...boundary, + children: boundary.children.map(filterRecursive), + }; + } + + // Filter children based on the filters + const filteredChildren = boundary.children + .filter((child) => boundaryFilters.some((f) => f.code === child.code && f.type === child.boundaryType)) + .map(filterRecursive); + + // Return the boundary with filtered children + return { + ...boundary, + children: filteredChildren, + }; + } + + // Map through the boundary data and apply the recursive filter function to each boundary + const filteredData = boundaryData.map(filterRecursive); + return filteredData; +}; + +/** + * Retrieves all facilities for a given tenant ID. + * @param tenantId The ID of the tenant. + * @returns An array of facilities. + */ +async function getAllFacilities(tenantId) { + // Retrieve all facilities for the given tenant ID + const facilitySearchBody = { + Facility: { isPermanent: true }, + }; + + const facilitySearchParams = { + limit: 50, + offset: 0, + tenantId: tenantId, + }; + + const searchedFacilities = []; + let searchAgain = true; + + while (searchAgain) { + const response = await getFacilities(facilitySearchParams, facilitySearchBody); + if (response) { + searchAgain = response.length >= 50; + searchedFacilities.push(...response); + facilitySearchParams.offset += 50; + } else searchAgain = false; + } + + return searchedFacilities; +} + +const addFacilitySheet = (xlsxData, mapping, facilities, schema, t) => { + if (!mapping) return xlsxData; + // Create header row + const headers = Object.keys(mapping); + + // Create data rows + const dataRow = []; + for (const facility of facilities) { + facility.isPermanent = facility.isPermanent ? t("PERMAENENT") : t("TEMPORARY"); + dataRow.push(headers.map((header) => facility[mapping[header]])); + } + headers.push(commonColumn); + const additionalCols = []; + if (schema?.schema?.Properties) { + const properties = Object.keys(schema.schema.Properties); + for (const col of properties) { + if (!headers.includes(col)) { + additionalCols.push(col); + } + } + } + headers.push(...additionalCols); + // Combine headers and data rows + const arrayOfArrays = [headers.map((item) => generateLocalisationKeyForSchemaProperties(item)), ...dataRow]; + + const facilitySheet = { + sheetName: FACILITY_DATA_SHEET, + data: arrayOfArrays, + }; + const updatedXlsxData = [facilitySheet, ...xlsxData]; + return updatedXlsxData; +}; + +const addReadMeSheet = (xlsxData, readMeData, readMeSheetName) => { + if (!readMeSheetName) return xlsxData; + const data = readMeData.reduce((acc, item) => { + if (item?.header) { + acc.push([item.header], ...(item.points || []).map((item) => [item]), [], [], [], []); + } + return acc; + }, []); + + const readMeSheet = { + sheetName: readMeSheetName, + data: [["MICROPLAN_TEMPLATE_README_MAIN_HEADER"], [], [], [], ...data], + }; + xlsxData.unshift(readMeSheet); + return xlsxData; +}; + +/** + * @param {Object} options + * @param {boolean} options.hierarchyLevelWiseSheets + * @param {string} options.hierarchyLevelName + * @param {boolean} options.addFacilityData + * @param {Object} options.schema + * @param {Object[]} options.boundaries + * @param {string} options.tenantId + * @param {string} options.hierarchyType + * @param {Object} options.readMeData + * @param {string} options.readMeSheetName + * @param {string} options.t // Assuming t is some context or translation object + */ +export const createTemplate = async ({ + hierarchyLevelWiseSheets = true, + hierarchyLevelName, + addFacilityData = false, + schema, + boundaries, + tenantId, + hierarchyType, + readMeData, + readMeSheetName, + t, +}) => { + // Fetch or retrieve boundary data + const filteredBoundaries = await fetchFilteredBoundaries(boundaries, tenantId, hierarchyType); + + // Initialize xlsxData array + let xlsxData = []; + + // Add boundary data to xlsxData + xlsxData = addBoundaryData(xlsxData, filteredBoundaries, hierarchyType); + + // Handle hierarchy level sheets + if (hierarchyLevelWiseSheets) { + xlsxData = devideXlsxDataHierarchyLevelWise(xlsxData, hierarchyLevelName); + } + + // Handle facility data addition + if (addFacilityData) { + xlsxData = await addFacilityDataToSheets(xlsxData, schema, tenantId, t); + } else { + // If no facility data, add schema data directly + xlsxData = addSchemaData(xlsxData, schema); + } + + // Add readme sheet data if provided + xlsxData = addReadMeSheet(xlsxData, readMeData, readMeSheetName); + + return xlsxData; +}; + +// Function to fetch filtered boundaries +const fetchFilteredBoundaries = async (boundaries, tenantId, hierarchyType) => { + const rootBoundary = boundaries?.find((boundary) => boundary.isRoot); + const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; + let boundaryData = sessionData.filteredBoundaries; + + if (!boundaryData) { + boundaryData = await fetchBoundaryData(tenantId, hierarchyType, rootBoundary?.code); + const filteredBoundaries = await filterBoundaries(boundaryData, boundaries); + Digit.SessionStorage.set("microplanHelperData", { + ...sessionData, + filteredBoundaries: filteredBoundaries, + }); + return filteredBoundaries; + } + return boundaryData; +}; + +// Function to add facility data to sheets +const addFacilityDataToSheets = async (xlsxData, schema, tenantId, t) => { + const facilities = await getAllFacilities(tenantId); + if (schema?.template?.facilitySchemaApiMapping) { + return addFacilitySheet(xlsxData, schema.template.facilitySchemaApiMapping, facilities, schema, t); + } + // If no specific facility schema mapping, add default facility data + const facilitySheet = { + sheetName: FACILITY_DATA_SHEET, + data: [], + }; + return addSchemaData([facilitySheet], schema); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js new file mode 100644 index 00000000000..b50b2ad48a6 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js @@ -0,0 +1,150 @@ +import { SHEET_PASSWORD, UNPROTECT_TILL_ROW } from "../configs/constants"; + +export function updateFontNameToRoboto(worksheet) { + worksheet.eachRow({ includeEmpty: true }, (row) => { + row.eachCell({ includeEmpty: true }, (cell) => { + // Preserve existing font properties + const existingFont = cell.font || {}; + + // Update only the font name to Roboto + cell.font = { + ...existingFont, // Spread existing properties + name: "Roboto", // Update the font name + }; + }); + }); +} + +export const freezeWorkbookValues = async (workbook) => { + workbook.eachSheet((worksheet) => { + worksheet.eachRow((row) => { + row.eachCell((cell) => { + // Lock each cell + cell.protection = { + locked: true, + }; + }); + }); + // Protect the worksheet + worksheet.protect(SHEET_PASSWORD, { + selectLockedCells: true, + selectUnlockedCells: true, + }); + }); + + return workbook; +}; + +export const unfreezeColumnsByHeader = async (workbook, headers) => { + workbook.eachSheet((worksheet) => { + const headerRow = worksheet.getRow(1); // Assuming headers are in the first row + const columnsToUnfreeze = []; + + headerRow.eachCell((cell, colNumber) => { + if (headers.includes(cell.value)) { + columnsToUnfreeze.push(colNumber); + } + }); + + worksheet.eachRow((row, rowNumber) => { + if (rowNumber === 1) return; + columnsToUnfreeze.forEach((colNumber) => { + const cell = row.getCell(colNumber); + cell.protection = { + locked: false, + }; + }); + }); + + // Re-protect the worksheet after modifying cell protection + worksheet.protect(SHEET_PASSWORD, { + selectLockedCells: true, + selectUnlockedCells: true, + }); + }); + + return workbook; +}; + +export const freezeSheetValues = async (workbook, sheetName) => { + const worksheet = workbook.getWorksheet(sheetName); + if (worksheet) { + worksheet.eachRow((row) => { + row.eachCell((cell) => { + // Lock each cell + cell.protection = { + locked: true, + }; + }); + }); + // Protect the worksheet + worksheet.protect(SHEET_PASSWORD, { + selectLockedCells: true, + selectUnlockedCells: true, + }); + } + + return workbook; +}; + +export const freezeCellsWithData = async (workbook, sheetName) => { + const worksheet = workbook.getWorksheet(sheetName); + if (worksheet) { + worksheet.eachRow((row) => { + row.eachCell((cell) => { + if (cell.value) { + // Check if the cell has data + cell.protection = { + locked: true, + }; + } else { + cell.protection = { + locked: false, + }; + } + }); + }); + // Protect the worksheet + worksheet.protect(SHEET_PASSWORD, { + selectLockedCells: true, + selectUnlockedCells: true, + }); + } + + return workbook; +}; +export const performUnfreezeCells = async (workbook, sheetName) => { + const sheet = workbook.getWorksheet(sheetName); + + let lastFilledColumn = 1; + sheet.getRow(1).eachCell((cell, colNumber) => { + if (cell.value !== undefined && cell.value !== null && cell.value !== "") { + lastFilledColumn = colNumber; + } + }); + + for (let row = 1; row <= parseInt(UNPROTECT_TILL_ROW); row++) { + for (let col = 1; col <= lastFilledColumn; col++) { + const cell = sheet.getCell(row, col); + if (!cell.value && cell.value !== 0) { + cell.protection = { locked: false }; + } + } + } + sheet.protect(SHEET_PASSWORD, { selectLockedCells: true, selectUnlockedCells: true }); +}; + +export const hideUniqueIdentifierColumn = async (workbook, sheetName, column) => { + const sheet = workbook.getWorksheet(sheetName); + for (const item of column) { + let colIndex; + sheet.getRow(1).eachCell((cell, colNumber) => { + if (cell.value === item) { + colIndex = colNumber; + } + }); + if (column && sheet.getColumn(colIndex)) { + sheet.getColumn(colIndex).hidden = true; + } + } +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js new file mode 100644 index 00000000000..0d2a344a8f1 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js @@ -0,0 +1,199 @@ +import Ajv from "ajv"; +const ajv = new Ajv({ allErrors: true }); +ajv.addKeyword("isRequired"); +ajv.addKeyword("isLocationDataColumns"); +ajv.addKeyword("isRuleConfigureInputs"); +ajv.addKeyword("isFilterPropertyOfMapSection"); +ajv.addKeyword("isVisualizationPropertyOfMapSection"); +ajv.addKeyword("toShowInMicroplanPreview"); + +// Function responsible for excel data validation with respect to the template/schema provided +const translateSchema = (schemaData) => { + const required = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRequired) { + acc.push(key); + } + return acc; + }, []); + + return { required, properties: schemaData.Properties }; +}; + +const createSchema = (properties, required) => { + return { + type: "object", + patternProperties: { + ".*": { + type: "array", + items: { + type: "object", + properties: properties, + required: required, + additionalProperties: true, + }, + }, + }, + minProperties: 1, + additionalProperties: false, + }; +}; + +const extractLocationDataColumns = (schemaData) => { + return Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isLocationDataColumns) { + acc.push(key); + } + return acc; + }, []); +}; + +const setNestedError = (errors, path, error) => { + if (!path.length) return; + + let current = errors; + for (let i = 0; i < path.length - 1; i++) { + if (!current[path[i]]) { + current[path[i]] = {}; + } + current = current[path[i]]; + } + + if (!current[path[path.length - 1]]) { + current[path[path.length - 1]] = []; + } + + current[path[path.length - 1]] = [...new Set([...current[path[path.length - 1]], error])]; +}; + +const formatErrors = (validateExcelErrors, locationDataColumns, t) => { + const errors = {}; + let hasDataErrors = "false"; // true, false, missing_properties, unknown + const missingColumnsList = new Set(); + let errorMessages = {}; + + validateExcelErrors.forEach((error) => { + let tempErrorStore = ""; + let instancePathTypeGlobal; + + switch (error.keyword) { + case "additionalProperties": + tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES"; + hasDataErrors = "true"; + break; + case "type": + { + const instancePathType = error.instancePath.split("/"); + const neededType = error.params?.type; + instancePathTypeGlobal = instancePathType; + tempErrorStore = locationDataColumns.includes(instancePathType[instancePathType.length - 1]) + ? "ERROR_INCORRECT_LOCATION_COORDINATES" + : neededType === "number" + ? "ERROR_MUST_BE_A_NUMBER" + : "ERROR_MUST_BE_A_STRING"; + hasDataErrors = "true"; + } + break; + case "required": + { + const missing = error.params.missingProperty; + const instancePathType = error.instancePath.split("/"); + instancePathTypeGlobal = [...instancePathType, missing]; + tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY"; + missingColumnsList.add(missing); + hasDataErrors = "true"; + } + break; + case "maximum": + case "minimum": + { + const instancePathMinMax = error.instancePath.split("/"); + instancePathTypeGlobal = instancePathMinMax; + tempErrorStore = locationDataColumns.includes(instancePathMinMax[instancePathTypeGlobal.length - 1]) + ? "ERROR_INCORRECT_LOCATION_COORDINATES" + : "ERROR_DATA_EXCEEDS_LIMIT_CONSTRAINTS"; + hasDataErrors = "true"; + } + break; + case "pattern": + tempErrorStore = "ERROR_VALUE_NOT_ALLOWED"; + hasDataErrors = "true"; + break; + case "minProperties": + hasDataErrors = "minProperties"; + break; + case "enum": + { + const instancePathType = error.instancePath.split("/"); + instancePathTypeGlobal = instancePathType; + tempErrorStore = { + error: "ERROR_UPLOAD_DATA_ENUM", + values: { allowedValues: error.params?.allowedValues?.map((item) => t(item)).join(", ") }, + }; + hasDataErrors = "true"; + } + break; + default: + hasDataErrors = "unknown"; + } + + if (tempErrorStore && instancePathTypeGlobal) { + setNestedError(errors, instancePathTypeGlobal.slice(1, 4), tempErrorStore); + } + + switch (hasDataErrors) { + case "true": + errorMessages = { dataError: "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS" }; + break; + case "minProperties": + errorMessages = { minProperties: "ERROR_UPLOADED_DATA_IS_EMPTY" }; + break; + case "unknown": + errorMessages = { unknown: "ERROR_UNKNOWN" }; + break; + case "false": + break; + } + }); + + return { + valid: !hasDataErrors, + message: errorMessages ? [...new Set(Object.values(errorMessages))] : [], + errors, + missingColumnsList, + }; +}; + +export const excelValidations = (data, schemaData, t) => { + const { required, properties } = translateSchema(schemaData); + const schema = createSchema(properties, required); + const validateExcel = ajv.compile(schema); + const valid = validateExcel(data); + const locationDataColumns = extractLocationDataColumns(schemaData); + + if (!valid) { + const validationResult = formatErrors(validateExcel.errors, locationDataColumns, t); + ajv.removeSchema(); + return validationResult; + } + + ajv.removeSchema(); + return { valid }; +}; + +export const checkForErrorInUploadedFileExcel = async (fileInJson, schemaData, t) => { + try { + const valid = excelValidations(fileInJson, schemaData, t); + if (valid.valid) { + return { valid: true }; + } + return { + valid: false, + message: valid.message, + errors: valid.errors, + missingProperties: valid.missingColumnsList, + }; + } catch (error) { + console.error("Error in excel validations: ", error?.message); + return { valid: false, message: ["ERROR_PARSING_FILE"] }; + } +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js new file mode 100644 index 00000000000..f2d4f277ba6 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js @@ -0,0 +1,99 @@ +import ExcelJS from "exceljs"; + +// input is a xlsx blob +// options {header} +// header: true -> have seperate header so data will be in key: value pair +export const parseXlsxToJsonMultipleSheets = async (file, options = {}) => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.onload = async (event) => { + try { + const arrayBuffer = event.target.result; + const workbook = await loadWorkbook(arrayBuffer); + const jsonData = processWorkbook(workbook, options); + resolve(jsonData); + } catch (error) { + console.error(error); + resolve({ error: true }); + } + }; + + reader.onerror = (error) => { + console.error(error); + resolve({ error: true, details: error }); + }; + + reader.readAsArrayBuffer(file); + }); +}; + +const loadWorkbook = async (arrayBuffer) => { + const workbook = new ExcelJS.Workbook(); + await workbook.xlsx.load(arrayBuffer); + return workbook; +}; + +const processWorkbook = (workbook, options) => { + const jsonData = {}; + workbook.eachSheet((worksheet) => { + const jsonSheetData = processSheet(worksheet, options); + if (jsonSheetData.length !== 0 && jsonSheetData?.[0].length !== 0) { + jsonData[worksheet.name] = jsonSheetData; + } + }); + return jsonData; +}; + +const processSheet = (worksheet, options) => { + const jsonSheetData = []; + let headers = []; + + worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => { + const rowData = cleanRowData(row.values); + if (options.header && rowNumber === 1) { + headers = rowData; + } else if (options.header && headers.length > 0) { + jsonSheetData.push(mapRowToHeaders(rowData, headers)); + } else { + jsonSheetData.push(rowData); + } + }); + + removeTrailingEmptyRows(jsonSheetData); + return jsonSheetData; +}; + +const cleanRowData = (rowData) => { + return rowData.slice(1).map((cell) => (typeof cell === "string" ? cell.trim() : cell)); +}; + +const mapRowToHeaders = (rowData, headers) => { + const rowObject = {}; + headers.forEach((header, index) => { + rowObject[header] = rowData[index]; + }); + return rowObject; +}; + +const removeTrailingEmptyRows = (data) => { + while (data.length > 0) { + const lastRow = data[data.length - 1]; + const isEmptyRow = checkIfRowIsEmpty(lastRow); + if (isEmptyRow) { + data.pop(); + } else { + break; + } + } +}; + +const checkIfRowIsEmpty = (row) => { + if (Array.isArray(row)) { + return row.filter((item) => item !== "").length === 0; + } + if (typeof row === "object" && row !== null) { + return Object.values(row).filter((item) => item !== "").length === 0; + } + return false; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js new file mode 100644 index 00000000000..42a465740b5 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js @@ -0,0 +1,234 @@ +import gjv from "geojson-validation"; +import Ajv from "ajv"; +const ajv = new Ajv({ allErrors: true }); +ajv.addKeyword("isRequired"); +ajv.addKeyword("isLocationDataColumns"); +ajv.addKeyword("isRuleConfigureInputs"); +ajv.addKeyword("isFilterPropertyOfMapSection"); +ajv.addKeyword("isVisualizationPropertyOfMapSection"); +ajv.addKeyword("toShowInMicroplanPreview"); + +//the postion must be valid point on the earth, x between -180 and 180 +gjv.define("Position", (position) => { + let errors = []; + if (position[0] < -180 || position[0] > 180) { + errors.push("Location Coordinates Error: the x must be between -180 and 180"); + } + if (position[1] < -90 || position[1] > 90) { + errors.push("Location Coordinates Error: the y must be between -90 and 90"); + } + return errors; +}); + +// Main functino for geojson validation that includes structural and property validations +export const geojsonValidations = (data, schemaData, t) => { + const valid = geojsonStructureValidation(data); + return valid.valid ? { valid: true } : { valid: false, message: valid.message || ["ERROR_INVALID_GEOJSON"] }; +}; + +// Funciton responsible for structural verification of geojson data +export const geojsonStructureValidation = (data) => { + let valid = true; + const trace = {}; + for (let i = 0; i < data["features"].length; i++) { + const check = gjv.valid(data["features"][i]); + valid = valid && check; + const errors = gjv.isFeature(data["features"][i], true); + // check if the location coordinates are according to the provided guidlines + if (errors.some((str) => str.includes("Location Coordinates Error:"))) return { valid: false, message: ["ERROR_INCORRECT_LOCATION_COORDINATES"] }; + if (!check) trace[i] = [errors]; + // let error; + // Object.keys(data["features"][i]["properties"]).forEach((j) => { + // if (j.length > 10) error = { valid: false, trace, message: ["ERROR_FIELD_NAME"] }; + // return j; + // }); + // if (error) return error; + } + return { valid, trace }; +}; + +const geometryValidation = (data) => { + let firstType; + for (const feature of data.features) { + if (!feature.geometry || !feature.geometry.type) { + return false; // Missing geometry or geometry type + } + if (!firstType) { + firstType = feature.geometry.type; + } else { + // Check if the current geometry type matches the first one + if (feature.geometry.type !== firstType) { + return false; // Different geometry types found + } + } + } + return true; +}; + +// Function responsible for property verification of geojson data +export const geojsonPropertiesValidation = (data, schemaData, name, t) => { + const translate = () => { + const required = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRequired) { + acc.push(key); + } + return acc; + }, []); + + // const properties = prepareProperties(schemaData.Properties, t); + return { required, properties: schemaData.Properties }; + }; + const { required, properties } = translate(); + const schema = { + type: "object", + properties: { + type: { const: "FeatureCollection" }, + }, + patternProperties: { + "^features$": { + type: "array", + items: { + type: "object", + patternProperties: { + "^properties$": { + type: "object", + patternProperties: properties, + required: required, + additionalProperties: true, + }, + }, + }, + }, + }, + additionalProperties: true, + }; + const validateGeojson = ajv.compile(schema); + const valid = validateGeojson(data); + const errors = {}; + let hasDataErrors = "false"; // true, false, missing_properties, unknown + const missingColumnsList = new Set(); + let errorMessages = []; + if (!valid) { + for (let i = 0; i < validateGeojson.errors.length; i++) { + let tempErrorStore = ""; + let instancePathTypeGlobal = validateGeojson.errors[i].instancePath.split("/"); + switch (validateGeojson.errors[i].keyword) { + case "additionalProperties": { + tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES"; + hasDataErrors = "true"; + break; + } + case "type": + { + const instancePathType = validateGeojson.errors[i].instancePath.split("/"); + const neededType = validateGeojson.errors[i].params?.type; + instancePathTypeGlobal = instancePathType; + tempErrorStore = neededType === "number" ? "ERROR_MUST_BE_A_NUMBER" : "ERROR_MUST_BE_A_STRING"; + hasDataErrors = "true"; + } + break; + case "const": { + if (validateGeojson.errors[i].params.allowedValue === "FeatureCollection") tempErrorStore = "ERROR_FEATURECOLLECTION"; + hasDataErrors = "true"; + break; + } + case "required": { + const missing = validateGeojson.errors[i].params.missingProperty; + const instancePathType = validateGeojson.errors[i].instancePath.split("/"); + instancePathTypeGlobal = [...instancePathType, missing]; + tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY"; + missingColumnsList.add(missing); + // hasDataErrors = "missing_properties"; + hasDataErrors = "true"; + break; + } + case "pattern": + tempErrorStore = "ERROR_VALUE_NOT_ALLOWED"; + hasDataErrors = "true"; + break; + case "minProperties": { + hasDataErrors = "minProperties"; + break; + } + case "enum": { + const instancePathType = validateGeojson.errors[i].instancePath.split("/"); + instancePathTypeGlobal = instancePathType; + tempErrorStore = { + error: "ERROR_UPLOAD_DATA_ENUM", + values: { allowedValues: validateGeojson.errors[i]?.params?.allowedValues?.map((item) => t(item)).join(", ") }, + }; + hasDataErrors = "true"; + break; + } + default: + hasDataErrors = "unknown"; + break; + } + if (tempErrorStore) + errors[name] = { + ...(errors[name] ? errors[name] : {}), + [instancePathTypeGlobal[2]]: { + ...(errors?.[name]?.[instancePathTypeGlobal[2]] ? errors?.[name]?.[instancePathTypeGlobal[2]] : {}), + [instancePathTypeGlobal[4]]: [ + ...new Set( + ...(errors?.[name]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[4]] + ? errors?.[name]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[4]] + : []) + ), + tempErrorStore, + ], + }, + }; + + switch (hasDataErrors) { + case "true": + errorMessages = { ...errorMessages, dataError: t("ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") }; + break; + case "unknown": + errorMessages = { ...errorMessages, unkown: t("ERROR_UNKNOWN") }; + break; + case "missing_properties": + errorMessages = { + ...errorMessages, + missingProperty: t("ERROR_MISSING_PROPERTY", { properties: [...missingColumnsList].map((item) => t(item)).join(", ") }), + }; + break; + case "false": + break; + } + } + + ajv.removeSchema(); + return { + valid: !hasDataErrors, + message: errorMessages ? [...new Set(Object.values(errorMessages))] : [], + errors, + validationError: validateGeojson.errors, + }; + } + ajv.removeSchema(); + if (!geometryValidation(data)) return { valid: false, message: t("ERROR_MULTIPLE_GEOMETRY_TYPES") }; + return { valid: true }; +}; + +//////////////////////////// +// // Might be needed +// function filterOutWordAndLocalise(inputString, operation) { +// // Define a regular expression to match the string parts +// var regex = /(\w+)/g; // Matches one or more word characters + +// // Replace each match using the provided function +// var replacedString = inputString.replace(regex, function (match) { +// // Apply the function to each matched string part +// return operation(match); +// }); + +// return replacedString; +// } +// const prepareProperties = (properties, t) => { +// let newProperties = {}; +// Object.keys(properties).forEach((item) => (newProperties[filterOutWordAndLocalise(item, t)] = properties[item])); +// return newProperties; +// }; + +//////////////////////////// diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js new file mode 100644 index 00000000000..0d21a93ca46 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js @@ -0,0 +1,478 @@ +import _ from "lodash"; +import { findChildren, findParent } from "../utils/processHierarchyAndData"; +import { EXCEL, LOCALITY, commonColumn } from "../configs/constants"; + +const formatDates = (value, type) => { + let newValue = value; + if (type !== "EPOC" && (!newValue || Number.isNaN(Number(newValue)))) { + newValue = new Date(); + } + switch (type) { + case "date": + return new Date(newValue)?.toISOString?.()?.split?.("T")?.[0]; + case "datetime": + return new Date(newValue).toISOString(); + case "EPOC": + return String(new Date(newValue)?.getTime()); + } +}; + +// get schema for validation +const getSchema = (campaignType, type, section, schemas) => { + if (!campaignType || !type || !section || !schemas) return {}; + return schemas.find((schema) => { + if (!schema.campaignType) { + return schema.type === type && schema.section === section; + } + return schema.campaignType === campaignType && schema.type === type && schema.section === section; + }); +}; + +// Sorting 2 lists, The first list is a list of string and second one is list of Objects +const sortSecondListBasedOnFirstListOrder = (firstList, secondList) => { + if (!firstList) return []; + // Create a map to store the indices of elements in the first list + const indexMap = {}; + firstList.forEach((value, index) => { + indexMap[value] = index; + }); + + // Sort the second list based on the order of elements in the first list + secondList.sort((objecta, objectb) => { + // Get the mappedTo values of each object + const mappedToA = objecta.mappedTo; + const mappedToB = objectb.mappedTo; + + // Get the indices of mappedTo values in the first list + const indexA = indexMap[mappedToA]; + const indexB = indexMap[mappedToB]; + + // Compare the indices + return indexA - indexB; + }); + + return secondList; +}; + +const computeGeojsonWithMappedProperties = ({ campaignType, fileType, templateIdentifier, validationSchemas }) => { + const schemaData = getSchema(campaignType, fileType, templateIdentifier, validationSchemas); + let schemaKeys; + if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"])); + // Sorting the resourceMapping list inorder to maintain the column sequence + const sortedSecondList = sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); + // Creating a object with input data with MDMS keys + const newFeatures = fileData.data["features"].map((item) => { + const newProperties = sortedSecondList.reduce( + (acc, e) => ({ + ...acc, + [e["mappedTo"]]: item["properties"][e["mappedFrom"]], + }), + {} + ); + item["properties"] = newProperties; + return item; + }); + const data = fileData.data; + data["features"] = newFeatures; + return data; +}; + +const destroySessionHelper = (currentPath, pathList, sessionName) => { + if (!pathList.includes(currentPath)) { + sessionStorage.removeItem(`Digit.${sessionName}`); + } +}; + +const convertGeojsonToExcelSingleSheet = (InputData, fileName) => { + if (!InputData || !Array.isArray(InputData) || InputData.length === 0) { + return null; + } + + // Extract keys from the first feature's properties + const keys = Object.keys(InputData?.[0]?.properties); + + if (!keys || keys.length === 0) { + return null; + } + + // Extract corresponding values for each feature + const values = InputData?.map((feature) => { + return keys.map((key) => feature.properties[key]); + }); + + // Group keys and values into the desired format + return { [fileName]: [keys, ...values] }; +}; + +const areObjectsEqual = (obj1, obj2) => { + return obj1.name === obj2.name && obj1.code === obj2.code; +}; + +const computeDifferences = (data1, data2) => { + const removed = {}; + const added = {}; + + for (const key in data1) { + if (Object.hasOwn(data2, key)) { + removed[key] = data1[key].filter((item1) => !data2[key].some((item2) => areObjectsEqual(item1, item2))); + added[key] = data2[key].filter((item2) => !data1[key].some((item1) => areObjectsEqual(item1, item2))); + } else { + removed[key] = data1[key]; + added[key] = []; + } + } + + for (const key in data2) { + if (!data1.hasOwnProperty(key)) { + added[key] = data2[key]; + removed[key] = []; + } + } + + return { removed, added }; +}; + +const extractNames = (data) => { + return Object.values(data) + .flatMap((items) => items) + .filter((item) => item.name) + .map((item) => item.name); +}; +// function that handles dropdown selection. used in: mapping and microplan preview +const handleSelection = (e, boundaryType, boundarySelections, hierarchy, setBoundarySelections, boundaryData, setIsLoading) => { + setIsLoading(true); + if (!e || !boundaryType) return; + const selections = e.map((item) => item?.[1]); + const newComputedSelection = { ...boundarySelections, [boundaryType]: selections }; + const { removed, added } = computeDifferences(boundarySelections, newComputedSelection); + // for(const item in removed){ + if (removed && Object.keys(removed).length !== 0 && Object.values(removed)?.flatMap((item) => item).length !== 0) { + const filteredRemoved = extractNames(removed); + const children = Object.values(findChildren(filteredRemoved, Object.values(boundaryData)?.[0]?.hierarchicalData))?.map((item) => item?.name); + for (const key in newComputedSelection) { + newComputedSelection[key] = newComputedSelection[key].filter((item) => !children.includes(item?.name)); + } + } + setBoundarySelections(newComputedSelection); +}; + +// Preventing default action when we scroll on input[number] is that it increments or decrements the number +const inputScrollPrevention = (e) => { + e.target.addEventListener("wheel", (e) => e.preventDefault(), { passive: false }); +}; + +const mapDataForApi = (data, Operators, microplanName, campaignId, status, reqType = "update") => { + const files = extractFiles(data, reqType); + const resourceMapping = extractResourceMapping(data, reqType); + const assumptions = extractAssumptions(data, reqType); + const operations = extractOperations(data, Operators, reqType); + + return createApiRequestBody(status, microplanName, campaignId, files, assumptions, operations, resourceMapping); +}; + +const extractFiles = (data, reqType) => { + const files = []; + if (data && data.upload) { + Object.values(data.upload).forEach((item) => { + if (isValidFile(item, reqType)) { + files.push(mapFile(item)); + } + }); + } + return files; +}; + +const isValidFile = (item, reqType) => { + if (!item || item.error || !item.filestoreId) return false; + if (reqType === "create" && !item.active) return false; + return true; +}; + +const mapFile = (item) => ({ + active: item.active, + filestoreId: item.filestoreId, + inputFileType: item.fileType, + templateIdentifier: item.section, + id: item.fileId, +}); + +const extractResourceMapping = (data, reqType) => { + let resourceMapping = []; + if (data && data.upload) { + Object.values(data.upload).forEach((item) => { + if (isValidResourceMapping(item, reqType)) { + resourceMapping.push(item.resourceMapping); + } + }); + resourceMapping = resourceMapping.flat(); + } + return resourceMapping; +}; + +const isValidResourceMapping = (item, reqType) => { + if (reqType === "create" && item.resourceMapping && item.resourceMapping.every((i) => i.active === false)) return false; + if (!item || !item.resourceMapping || item.error || !Array.isArray(item.resourceMapping)) return false; + if (!item.resourceMapping.every((i) => i.mappedFrom && i.mappedTo)) return false; + return true; +}; + +const extractAssumptions = (data, reqType) => { + if (!data || !data.hypothesis) return []; + return data.hypothesis.reduce((acc, item) => { + if (isValidAssumption(item, reqType)) { + acc.push({ ...item }); + } + return acc; + }, []); +}; + +const isValidAssumption = (item, reqType) => { + if (reqType === "create" && !item.active) return false; + if (!item.key || !item.value) return false; + return true; +}; + +const extractOperations = (data, Operators, reqType) => { + if (!data || !data.ruleEngine) return []; + return data.ruleEngine.reduce((acc, item) => { + if (isValidOperation(item, reqType)) { + acc.push(mapOperation(item, Operators)); + } + return acc; + }, []); +}; + +const isValidOperation = (item, reqType) => { + if (reqType === "create" && !item.active) return false; + if (!item.active && !item.input) return true; + if (!item.active && !item.operator && !item.output && !item.input && !item.assumptionValue) return false; + return true; +}; + +const mapOperation = (item, Operators) => { + const data = { ...item }; + const operator = Operators.find((e) => e.name === data.operator); + if (operator && operator.code) data.operator = operator.code; + if (data.oldInput) data.input = data.oldInput; + return data; +}; + +const createApiRequestBody = (status, microplanName, campaignId, files, assumptions, operations, resourceMapping) => ({ + PlanConfiguration: { + status, + tenantId: Digit.ULBService.getStateId(), + name: microplanName, + executionPlanId: campaignId, + files, + assumptions, + operations, + resourceMapping, + }, +}); + +const addResourcesToFilteredDataToShow = (previewData, resources, hypothesisAssumptionsList, formulaConfiguration, userEditedResources, t) => { + // Clone the preview data to avoid mutating the original data + const data = _.cloneDeep(previewData); + + // Helper function to check for user-edited data + const checkUserEditedData = (commonColumnData, resourceName) => { + if (userEditedResources && userEditedResources[commonColumnData]) { + return userEditedResources[commonColumnData][resourceName]; + } + }; + + // Ensure the previewData has at least one row and the first row is an array + if (!Array.isArray(data) || !Array.isArray(data[0])) { + return []; + } + + // Identify the index of the common column + const conmmonColumnIndex = data[0].indexOf(commonColumn); + if (conmmonColumnIndex === -1) { + return []; + } + + // Ensure resources is a valid array + if (!Array.isArray(resources)) { + return data; + } + + // Process each row of the data + const combinedData = data.map((item, index) => { + if (!Array.isArray(item)) { + return item; + } + + if (index === 0) { + // Add resource names to the header row + resources.forEach((e) => item.push(e)); + return item; + } + + // Process each resource for the current row + resources.forEach((resourceName, resourceIndex) => { + let savedData = checkUserEditedData(item[conmmonColumnIndex], resourceName); + if (savedData !== undefined) { + item.push(savedData); + } else { + let calculations = calculateResource(resourceName, item, formulaConfiguration, previewData[0], hypothesisAssumptionsList, t); + if (calculations !== null) calculations = Math.round(calculations); + item.push(calculations !== null && calculations !== undefined ? calculations : undefined); + } + }); + + return item; + }); + + return combinedData; +}; + +const calculateResource = (resourceName, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t) => { + let formula = formulaConfiguration?.find((item) => item?.active && item?.output === resourceName); + if (!formula) return null; + + // Finding Input + // check for Uploaded Data + const inputValue = findInputValue(formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t); + if (inputValue === undefined || inputValue === null) return null; + const assumptionValue = hypothesisAssumptionsList?.find((item) => item?.active && item?.key === formula?.assumptionValue)?.value; + if (assumptionValue === undefined) return null; + + return findResult(inputValue, assumptionValue, formula?.operator); +}; + +// function to find input value, it calls calculateResource fucntion recurcively until it get a proper value +const findInputValue = (formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t) => { + const inputIndex = headers?.indexOf(formula?.input); + if (inputIndex === -1 || !rowData[inputIndex]) { + // let tempFormula = formulaConfiguration.find((item) => item?.output === formula?.input); + return calculateResource(formula?.input, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t); + } else return rowData[inputIndex]; +}; + +const findResult = (inputValue, assumptionValue, operator) => { + switch (operator) { + case "DEVIDED_BY": + if (assumptionValue === 0) return; + return inputValue / assumptionValue; + case "MULTIPLIED_BY": + return inputValue * assumptionValue; + case "ADDITION": + return inputValue + assumptionValue; + case "SUBSTRACTION": + return inputValue - assumptionValue; + case "RAISE_TO": + return inputValue ** assumptionValue; + default: + return; + } +}; + +const fetchData = (state, campaignType) => { + let hypothesis = []; + let rulesOutputs = []; + let uploadList = []; + + hypothesis = state?.HypothesisAssumptions?.find((item) => item.campaignType === campaignType)?.assumptions; + rulesOutputs = state?.RuleConfigureOutput?.find((item) => item.campaignType === campaignType)?.data; + uploadList = state?.UploadConfiguration?.reduce((acc, item) => { + if (item.required) acc.push(item.id); + return acc; + }, []); + return { hypothesisList: hypothesis, rulesOutputs, uploadList }; +}; +const hypothesisCheck = (hypothesis, validList) => { + if (hypothesis && Array.isArray(hypothesis) && hypothesis.length !== 0 && validList && Array.isArray(validList) && validList.length !== 0) { + return hypothesis.filter((item) => item.active).every((item) => validList.includes(item.key)); + } + return false; +}; +const ruleOutputCheck = (rules, ruleOuputList) => { + if ( + rules && + Array.isArray(rules) && + rules.filter((item) => item.active).length !== 0 && + ruleOuputList && + Array.isArray(ruleOuputList) && + ruleOuputList.length !== 0 + ) { + return rules.filter((item) => item.active).every((item) => ruleOuputList.includes(item.output)); + } + return false; +}; +const emptyRuleCheck = (rules) => { + return !rules || rules.filter((item) => item.active && Object.values(item)?.filter((e) => e === "").length !== 0).length === 0; +}; +const ruleHypothesisCheck = (rules, ruleHypothesis) => { + if (rules && Array.isArray(rules) && rules.length !== 0 && ruleHypothesis && Array.isArray(ruleHypothesis) && ruleHypothesis.length !== 0) { + return rules.filter((item) => item.active).every((item) => ruleHypothesis.includes(item.assumptionValue)); + } + return false; +}; +const uploadCheck = (uploads, uploadList) => { + if (uploads && Array.isArray(uploads) && uploads.length !== 0 && uploadList && Array.isArray(uploadList) && uploadList.length !== 0) { + return uploads.some((item) => uploadList.includes(item.templateIdentifier) && item.active); + } + return false; +}; +const planConfigRequestBodyValidator = (data, state, campaignType) => { + if (!data || !campaignType || !state) return false; + + const { hypothesisList, rulesOutputs, uploadList } = fetchData(state, campaignType); + let checks = + // microplan name check + (!data || !data.name) && + hypothesisCheck(data?.PlanConfiguration?.assumptions, hypothesisList) && + emptyRuleCheck(data?.PlanConfiguration?.operations) && + ruleOutputCheck(data?.PlanConfiguration?.operations, rulesOutputs) && + ruleHypothesisCheck( + data?.PlanConfiguration?.operations, + data?.PlanConfiguration?.assumptions?.filter((item) => item.active)?.map((item) => item.key) + ) && + uploadCheck(data?.PlanConfiguration?.files, uploadList); + return checks; + // if() +}; + +const processDropdownForNestedMultiSelect = (dropDownOptions) => { + if (!dropDownOptions) return dropDownOptions; + const result = dropDownOptions.reduce((acc, item) => { + const { parent, ...rest } = item; + + // Find the group by parentBoundaryType + let group = acc.find((g) => g.name === parent?.name); + + // If not found, create a new group + if (!group) { + group = { name: parent?.name, options: [] }; + acc.push(group); + } + + // Add the item to the options of the found/created group + group.options.push(rest); + + return acc; + }, []); + return result; +}; + +const transformIntoLocalisationCode = (code) => { + return code?.toUpperCase(); +}; + +export default { + formatDates, + computeGeojsonWithMappedProperties, + destroySessionHelper, + mapDataForApi, + inputScrollPrevention, + handleSelection, + convertGeojsonToExcelSingleSheet, + sortSecondListBasedOnFirstListOrder, + addResourcesToFilteredDataToShow, + calculateResource, + planConfigRequestBodyValidator, + getSchema, + processDropdownForNestedMultiSelect, + transformIntoLocalisationCode, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js new file mode 100644 index 00000000000..ae470038a91 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js @@ -0,0 +1,72 @@ +import ExcelJS from "exceljs"; +import { SHEET_COLUMN_WIDTH } from "../configs/constants"; + +export const convertJsonToXlsx = async (jsonData, columnWithStyle, returnWorkbook = false) => { + const workbook = new ExcelJS.Workbook(); + + for (const [sheetName, data] of Object.entries(jsonData)) { + const worksheet = workbook.addWorksheet(sheetName); + populateWorksheet(worksheet, data, columnWithStyle); + } + + if (returnWorkbook) return workbook; + return await writeWorkbookToBuffer(workbook); +}; + +const populateWorksheet = (worksheet, data, columnWithStyle) => { + data.forEach((row, rowIndex) => { + const newRow = worksheet.addRow(row); + if (columnWithStyle?.errorColumn && rowIndex > 0) { + applyStyleToColumn(newRow, data[0], columnWithStyle); + } + }); + + styleHeaderRow(worksheet); + setColumnWidths(worksheet); +}; + +/** + * Applies a specified style to a column in a given row of a spreadsheet. + * + * @param {Object} newRow - The row object where the style will be applied. + * @param {Array} headerRow - The header row array containing column names. + * @param {Object} columnWithStyle - An object containing the column name and the style to be applied. + * @param {string} columnWithStyle.errorColumn - The name of the column where the style should be applied. + * @param {Object} columnWithStyle.style - The style properties to be applied to the cell. + */ +const applyStyleToColumn = (newRow, headerRow, columnWithStyle) => { + const errorColumnIndex = headerRow.indexOf(columnWithStyle.errorColumn); + if (errorColumnIndex !== -1) { + const columnIndex = errorColumnIndex + 1; + const newCell = newRow.getCell(columnIndex); + if (columnWithStyle.style && newCell) { + for (const key in columnWithStyle.style) { + newCell[key] = columnWithStyle.style[key]; + } + } + } +}; + +const styleHeaderRow = (worksheet) => { + const headerRow = worksheet.getRow(1); + if (headerRow) { + headerRow.font = { bold: true }; + } +}; + +const setColumnWidths = (worksheet) => { + // Iterate over all rows in the worksheet + worksheet.eachRow((worksheetRow, rowNumber) => { + worksheetRow.eachCell((cell, colNumber) => { + // Update column width based on the length of the cell's text + const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width + const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding + worksheet.getColumn(colNumber).width = newWidth; + }); + }); +}; + +export const writeWorkbookToBuffer = async (workbook) => { + const buffer = await workbook.xlsx.writeBuffer({ compression: true }); + return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js new file mode 100644 index 00000000000..f742ffd5e47 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js @@ -0,0 +1,760 @@ +import L from "leaflet"; +import "leaflet/dist/leaflet.css"; +import { processHierarchyAndData, findChildren, calculateAggregateForTree } from "../utils/processHierarchyAndData"; +import { EXCEL, GEOJSON, SHAPEFILE, MapChoroplethGradientColors } from "../configs/constants"; +import { PopulationSvg } from "../icons/Svg"; +import chroma from "chroma-js"; +import * as MicroplanIconCollection from "../icons/Svg"; +import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; + +const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs }; + +export const generatePreviewUrl = (baseMapUrl, center = [0, 0], zoom = 5) => { + const lon = Math.floor(((center[1] + 180) / 360) * Math.pow(0, zoom)); + const lat = Math.floor( + ((1 - Math.log(Math.tan((center[0] * Math.PI) / 180) + 1 / Math.cos((center[0] * Math.PI) / 180)) / Math.PI) / 2) * Math.pow(2, zoom) + ); + if (baseMapUrl) { + return baseMapUrl.replace("{z}", zoom).replace("{x}", lat).replace("{y}", lon); + } + // Return a default preview URL or handle this case as needed + return "default-preview-url.jpg"; // todo +}; + +// get schema for validation +export const getSchema = (campaignType, type, section, schemas) => { + return schemas.find((schema) => { + if (!schema.campaignType) { + return schema.type === type && schema.section === section; + } + return schema.campaignType === campaignType && schema.type === type && schema.section === section; + }); +}; + +export const calculateAggregateForTreeMicroplanWrapper = (entity) => { + if (!entity || typeof entity !== "object") return {}; + let newObject = {}; + for (let [key, value] of Object.entries(entity)) { + if (!value?.["hierarchicalData"]) continue; + let aggregatedTree = calculateAggregateForTree(value?.["hierarchicalData"]); + newObject[key] = { ...value, hierarchicalData: aggregatedTree }; + } + return newObject; +}; + +export const extractGeoData = ( + campaignType, + microplanData, + filterDataOrigin, + validationSchemas, + setToast, + setDataAvailability, + hierarchy, + setBoundaryData, + setFilterData, + setFilterProperties, + setFilterSelections, + setFilterPropertyNames, + state, + setChoroplethProperties, + setDataCompleteness, + t +) => { + if (!hierarchy) return; + + const initializeDataAvailability = (microplanData) => (microplanData?.upload ? "initialStage" : undefined); + + const checkFileActivity = (fileData) => fileData.active; + + const checkFileSection = (fileData, filterDataOrigin) => + filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section) || filterDataOrigin?.layerDataOrigin?.includes(fileData?.section); + + const getFileValidationSchema = (campaignType, fileData, validationSchemas) => + getSchema(campaignType, fileData?.fileType, fileData?.section, validationSchemas); + + const updateDataAvailabilityCheck = (dataAvailabilityCheck, condition, partialState) => + condition ? partialState : dataAvailabilityCheck === "initialStage" ? "false" : partialState; + + const handleFileDataError = (dataAvailabilityCheck, fileData) => + fileData?.error ? updateDataAvailabilityCheck(dataAvailabilityCheck, true, "partial") : dataAvailabilityCheck; + + const addResourcesToFilteredData = (data, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t) => + Digit.Utils.microplan.addResourcesToFilteredDataToShow( + data, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + microplanData?.microplanPreview?.userEditedResources || [], + t + ); + + const processFileData = ( + fileData, + schema, + filterDataOrigin, + virtualizationPropertiesCollector, + filterPropertiesCollector, + filterPropertieNameCollector, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + t + ) => { + const properties = Object.entries(schema?.schema?.Properties || {}); + const latLngColumns = []; + const filterProperty = []; + + for (const [key, value] of properties) { + if (value?.isLocationDataColumns) latLngColumns.push(t(key)); + if (filterDataOrigin?.layerDataOrigin?.includes(fileData?.section) && value?.isFilterPropertyOfMapSection) filterProperty.push(key); + if (value?.isVisualizationPropertyOfMapSection && filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section)) + virtualizationPropertiesCollector.add(key); + } + + filterProperty.forEach((property) => filterPropertieNameCollector.add(property)); + + return { latLngColumns, filterProperty }; + }; + + const processExcelFile = (fileData, latLngColumns, resources, formulaConfiguration, hypothesisAssumptionsList, schema, t) => { + let dataAvailabilityCheck = "true"; + const columnList = Object.values(fileData?.data)?.[0]?.[0]; + const check = latLngColumns.every((colName) => columnList.includes(t(colName))); + + if (!check) dataAvailabilityCheck = "partial"; + + let dataWithResources = Object.values(fileData?.data); + if (resources && formulaConfiguration && hypothesisAssumptionsList && schema?.showResourcesInMappingSection) { + dataWithResources = dataWithResources.map((item) => + addResourcesToFilteredData(item, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t) + ); + } + + const hasLocationData = dataWithResources.some((item) => item.some((row) => row.includes("lat") && row.includes("long"))); + + const convertedData = dataWithResources.map((item) => + item.map((row, rowIndex) => { + if (rowIndex === 0) { + if (row.indexOf("features") === -1) row.push("feature"); + return row; + } + const latIndex = item[0].findIndex((cell) => cell === "lat"); + const lonIndex = item[0].findIndex((cell) => cell === "long"); + const properties = item[0].reduce((acc, cell, index) => ({ ...acc, [cell]: row[index] }), {}); + const feature = + latIndex !== -1 && lonIndex !== -1 + ? { + type: "Feature", + properties, + geometry: { + type: "Point", + coordinates: [row[lonIndex], row[latIndex]], + }, + } + : null; + row.push(feature); + return row; + }) + ); + + return { dataAvailabilityCheck, hasLocationData, convertedData }; + }; + + const processGeoJsonFile = (fileData, filterProperty, resources, formulaConfiguration, hypothesisAssumptionsList, t) => { + const dataAvailabilityCheck = "true"; + const keys = [...Object.keys(fileData?.data.features[0].properties), "feature"]; + const values = fileData?.data.features.map((feature) => keys.map((key) => (key === "feature" ? feature : feature.properties[key] || null))); + + const dataWithResources = [[...keys, ...resources], ...values]; + const processedDataWithResources = dataWithResources.map((item, index) => { + if (index === 0) return item; + const newProperties = keys.reduce((acc, key, i) => (key !== "feature" ? { ...acc, [key]: item[i] } : acc), {}); + item[item.length - 1] = { ...item[item.length - 1], properties: newProperties }; + return item; + }); + + return { dataAvailabilityCheck, dataWithResources: processedDataWithResources }; + }; + + const updateFilterPropertiesCollector = (fileData, filterProperty, filterPropertiesCollector) => { + filterProperty.forEach((item) => { + Object.values(fileData?.data).forEach((data) => { + const filterPropertyIndex = data[0].indexOf(item); + if (filterPropertyIndex !== -1) data.slice(1).forEach((e) => filterPropertiesCollector.add(e[filterPropertyIndex])); + }); + }); + }; + + const setAvailabilityAndToastMessages = (dataAvailabilityCheck, combineList, files, setToast, t) => { + if (dataAvailabilityCheck === "true") { + const sectionWiseCheck = combineList.every((item) => Object.keys(files).includes(item)); + if (!sectionWiseCheck) dataAvailabilityCheck = "partial"; + } + + if (dataAvailabilityCheck === "initialStage" && (combineList.length === 0 || Object.keys(files).length === 0)) dataAvailabilityCheck = "false"; + + const toastMessages = { + false: { state: "warning", message: t("MAPPING_NO_DATA_TO_SHOW") }, + partial: { state: "warning", message: t("MAPPING_PARTIAL_DATA_TO_SHOW") }, + undefined: { state: "error", message: t("MAPPING_NO_DATA_TO_SHOW") }, + }; + + setToast(toastMessages[dataAvailabilityCheck]); + return dataAvailabilityCheck; + }; + + const setFinalDataAndProperties = ( + dataAvailabilityCheck, + setBoundary, + setFilter, + setBoundaryData, + setFilterData, + setFilterProperties, + setFilterSelections, + setFilterPropertyNames, + filterPropertiesCollector, + filterPropertieNameCollector, + virtualizationPropertiesCollector, + setChoroplethProperties, + resources + ) => { + setDataCompleteness(dataAvailabilityCheck); + setBoundary = calculateAggregateForTreeMicroplanWrapper(setBoundary); + setFilter = calculateAggregateForTreeMicroplanWrapper(setFilter); + setBoundaryData((previous) => ({ ...previous, ...setBoundary })); + setFilterData((previous) => ({ ...previous, ...setFilter })); + setFilterProperties([...filterPropertiesCollector]); + setFilterSelections([...filterPropertiesCollector]); + setFilterPropertyNames([...filterPropertieNameCollector]); + const tempVirtualizationPropertiesCollectorArray = [...virtualizationPropertiesCollector]; + if (tempVirtualizationPropertiesCollectorArray.length !== 0) + setChoroplethProperties([...tempVirtualizationPropertiesCollectorArray, ...(resources || [])]); + }; + + let setBoundary = {}; + let setFilter = {}; + const virtualizationPropertiesCollector = new Set(); + const filterPropertiesCollector = new Set(); + const filterPropertieNameCollector = new Set(); + const resources = state?.Resources?.find((item) => item.campaignType === campaignType)?.data; + const hypothesisAssumptionsList = microplanData?.hypothesis; + const formulaConfiguration = microplanData?.ruleEngine; + + let dataAvailabilityCheck = initializeDataAvailability(microplanData); + if (!dataAvailabilityCheck) return setToast({ state: "error", message: t("MAPPING_NO_DATA_TO_SHOW") }); + + const files = _.cloneDeep(microplanData.upload); + for (const fileData of files) { + if (!checkFileActivity(fileData) || !checkFileSection(fileData, filterDataOrigin)) { + dataAvailabilityCheck = "false"; + continue; + } + + if (!fileData?.fileType || !fileData?.section) continue; + + const schema = getFileValidationSchema(campaignType, fileData, validationSchemas); + dataAvailabilityCheck = handleFileDataError(dataAvailabilityCheck, fileData); + + const { latLngColumns, filterProperty } = processFileData( + fileData, + schema, + filterDataOrigin, + virtualizationPropertiesCollector, + filterPropertiesCollector, + filterPropertieNameCollector, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + t + ); + + if (fileData?.data && Object.keys(fileData?.data).length > 0) { + switch (fileData?.fileType) { + case EXCEL: + const { dataAvailabilityCheck: excelDataAvailabilityCheck, hasLocationData, convertedData } = processExcelFile( + fileData, + latLngColumns, + resources, + formulaConfiguration, + hypothesisAssumptionsList, + schema, + t + ); + dataAvailabilityCheck = excelDataAvailabilityCheck; + if (hasLocationData) updateFilterPropertiesCollector(fileData, filterProperty, filterPropertiesCollector); + const { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } = processHierarchyAndData(hierarchy, convertedData); + if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData.section)) + setBoundary = { ...setBoundary, [fileData.section]: { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } }; + else if (filterDataOrigin?.layerDataOrigin?.includes(fileData.section)) + setFilter = { ...setFilter, [fileData.section]: { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } }; + break; + case GEOJSON: + case SHAPEFILE: + const { dataAvailabilityCheck: geoJsonDataAvailabilityCheck, dataWithResources } = processGeoJsonFile( + fileData, + filterProperty, + resources, + formulaConfiguration, + hypothesisAssumptionsList, + t + ); + dataAvailabilityCheck = geoJsonDataAvailabilityCheck; + const { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData } = processHierarchyAndData(hierarchy, [ + dataWithResources, + ]); + if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData.section)) + setBoundary = { + ...setBoundary, + [fileData.section]: { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData }, + }; + else if (filterDataOrigin?.layerDataOrigin?.includes(fileData.section)) + setFilter = { ...setFilter, [fileData.section]: { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData } }; + break; + default: + break; + } + } + } + + const combineList = [...(filterDataOrigin?.boundriesDataOrigin || []), ...(filterDataOrigin?.layerDataOrigin || [])]; + dataAvailabilityCheck = setAvailabilityAndToastMessages(dataAvailabilityCheck, combineList, files, setToast, t); + + setFinalDataAndProperties( + dataAvailabilityCheck, + setBoundary, + setFilter, + setBoundaryData, + setFilterData, + setFilterProperties, + setFilterSelections, + setFilterPropertyNames, + filterPropertiesCollector, + filterPropertieNameCollector, + virtualizationPropertiesCollector, + setChoroplethProperties, + resources + ); +}; + +//prepare geojson to show on the map +export const prepareGeojson = (boundaryData, selection, style = {}) => { + if (!boundaryData || Object.keys(boundaryData).length === 0) return []; + let geojsonRawFeatures = []; + if (selection === "ALL") { + for (let data of Object.values(boundaryData)) { + const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); + if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; + } + } else if (Array.isArray(selection)) { + for (let data of Object.values(boundaryData)) { + const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); + if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; + } + } + + return geojsonRawFeatures.filter(Boolean); +}; +export const fetchFeatures = (data, parameter = "ALL", outputList = [], addOn = {}) => { + let tempStorage = []; + if (parameter === "ALL") { + // outputList(Object.values(data).flatMap(item=>item?.data?.feature)) + for (let [entityKey, entityValue] of Object.entries(data)) { + if (entityValue?.data?.feature) { + let feature = entityValue.data.feature; + feature.properties["name"] = entityKey; + feature.properties["addOn"] = addOn; + if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + else tempStorage = [...tempStorage, feature]; + } else { + tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + } + } + return tempStorage; + } + if (Array.isArray(parameter)) { + for (let [entityKey, entityValue] of Object.entries(data)) { + if (parameter.includes(entityKey) && entityValue && entityValue.data && entityValue.data.feature) { + let feature = entityValue.data.feature; + feature.properties["name"] = entityKey; + feature.properties["addOn"] = addOn; + if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + else tempStorage = [...tempStorage, feature]; + } + if (entityValue?.children) tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + } + return tempStorage; + } +}; + +export const addChoroplethProperties = (geojson, choroplethProperty, filteredSelection) => { + // Calculate min and max values of the property + const values = geojson.map((feature) => feature.properties[choroplethProperty]).filter((item) => !!item || item === 0) || []; + if (!values || values.length === 0) return []; + const convertedValues = values.map((item) => (!isNaN(item) ? item : 0)); + const minValue = Math.min(...convertedValues); + const maxValue = Math.max(...convertedValues); + + // Create a new geojson object + const newGeojson = geojson.map((feature) => { + const newFeature = { ...feature, properties: { ...feature.properties, addOn: { ...feature.properties.addOn } } }; + let color; + + if (choroplethProperty) { + color = interpolateColor(newFeature.properties[choroplethProperty], minValue, maxValue, MapChoroplethGradientColors); + } + + newFeature.properties.addOn.fillColor = color; + newFeature.properties.addOn.color = "rgba(0, 0, 0, 1)"; + if (!filteredSelection || filteredSelection.length === 0 || filteredSelection.includes(newFeature.properties.name)) { + newFeature.properties.addOn.fillOpacity = 1; + } else { + newFeature.properties.addOn.fillOpacity = 0.4; + newFeature.properties.addOn.opacity = 0.7; + } + + return newFeature; + }); + return newGeojson; +}; + +/** + * filterGeojsons : json + * filterSelection : array + * MapFilters : + */ +export const addFilterProperties = (filterGeojsons, filterSelections, filterPropertyNames, iconMapping) => { + try { + if (!filterGeojsons || !iconMapping || !filterSelections) return []; + let newFilterGeojson = []; + filterGeojsons.forEach((item) => { + if (filterPropertyNames && filterPropertyNames.length !== 0 && item.properties) { + let icon; + filterPropertyNames.forEach((name) => { + if (item.properties[name]) { + let temp = item.properties[name]; + if (!filterSelections.includes(temp)) return; + temp = iconMapping?.find((e) => e?.name == temp)?.icon?.marker; + let DynamicIcon = IconCollection?.[temp]; + if (typeof DynamicIcon === "function") { + icon = L.divIcon({ + className: "custom-svg-icon", + html: DynamicIcon({}), + iconAnchor: [25, 50], + }); + newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); + } else { + icon = DefaultMapMarker({}); + newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); + } + } + }); + } + return item; + }); + return newFilterGeojson; + } catch (error) { + console.error(error.message); + } +}; + +/** + * map: map + * geojson: geojson + * t: translator + */ + +export const addGeojsonToMap = (map, geojson, t) => { + try { + if (!map || !geojson) return false; + const geojsonLayer = L.geoJSON(geojson, { + style: (feature) => { + if (Object.keys(feature.properties.addOn).length !== 0) { + return feature.properties.addOn; + } + return { + weight: 2, + opacity: 1, + color: "rgba(176, 176, 176, 1)", + fillColor: "rgb(0,0,0,0)", + // fillColor: choroplethProperty ? color : "rgb(0,0,0,0)", + fillOpacity: 0, + // fillOpacity: choroplethProperty ? (feature?.properties?.style?.fillOpacity ? feature.properties.style.fillOpacity : 0.7) : 0, + }; + }, + pointToLayer: (feature, latlng) => { + if (feature.properties.addOn.icon) { + let icon = feature.properties.addOn.icon; + if (icon) { + return L.marker(latlng, { + icon: icon, + }); + } + } + return L.marker(latlng, { + icon: MapMarker(feature.properties.addOn), + }); + }, + onEachFeature: (feature, layer) => { + let popupContent; + popupContent = "
"; + popupContent += "
"; + popupContent += `
${feature.properties["name"]}
`; + for (let prop in feature.properties) { + if (prop !== "name" && prop !== "addOn" && prop !== "feature") { + let data = feature.properties[prop] ? feature.properties[prop] : t("NO_DATA"); + popupContent += + ""; + } + } + popupContent += "
" + + t(prop) + + "" + + data + + "
"; + layer.bindPopup(popupContent, { + minWidth: "28rem", + padding: "0", + }); + // Adjust map here when pop up closes + layer.on("popupclose", () => { + map.fitBounds(geojsonLayer.getBounds()); + }); + layer.on({ + mouseover: (e) => { + const layer = e.target; + if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { + return; + } + if (layer.setStyle) + layer.setStyle({ + weight: 2.7, + opacity: 1, + color: "rgba(255, 255, 255, 1)", + }); + // layer.openPopup(); + }, + mouseout: (e) => { + const layer = e.target; + if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { + return; + } + if (layer.setStyle) { + if (layer.feature.properties.addOn && Object.keys(layer.feature.properties.addOn).length !== 0) + layer.setStyle({ + ...layer.feature.properties.addOn, + }); + else + layer.setStyle({ + weight: 2, + color: "rgba(176, 176, 176, 1)", + }); + } + // layer.closePopup(); + }, + }); + }, + }); + geojsonLayer.addTo(map); + return geojsonLayer; + } catch (error) { + console.error(error.message); + } +}; + +export const interpolateColor = (value, minValue, maxValue, colors) => { + // Handle case where min and max values are the same + if (minValue === maxValue) { + // Return a default color or handle the case as needed + return colors[0].color; + } + + // Normalize the value to a percentage between 0 and 100 + const percent = !isNaN(value) ? ((value - minValue) / (maxValue - minValue)) * 100 : 0; + // Find the two colors to interpolate between + let lowerColor, upperColor; + for (let i = 0; i < colors.length - 1; i++) { + if (!isNaN(percent) && percent >= colors[i].percent && percent <= colors[i + 1].percent) { + lowerColor = colors[i]; + upperColor = colors[i + 1]; + break; + } + } + // Interpolate between the two colors + const t = (percent - lowerColor.percent) / (upperColor.percent - lowerColor.percent); + return chroma.mix(lowerColor.color, upperColor.color, t, "lab").hex(); +}; + +// Find bounds for multiple geojson together +export const findBounds = (data, buffer = 0.1) => { + if (!Array.isArray(data) || data.length === 0) { + return null; + } + + // Initialize variables to store bounds + var minLat = Number.MAX_VALUE; + var maxLat = -Number.MAX_VALUE; + var minLng = Number.MAX_VALUE; + var maxLng = -Number.MAX_VALUE; + + // Iterate through the data to find bounds + data.forEach(function (feature) { + if (!feature || !feature.geometry || !feature.geometry.type || !feature.geometry.coordinates) { + return null; + } + + var coords = feature.geometry.coordinates; + var geometryType = feature.geometry.type; + + switch (geometryType) { + case "Point": + var coord = coords; + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + break; + case "MultiPoint": + coords.forEach(function (coord) { + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + }); + break; + case "LineString": + case "MultiLineString": + case "Polygon": + case "MultiPolygon": + coords.forEach(function (polygons) { + if ((geometryType === "Polygon" || geometryType === "MultiPolygon") && Array.isArray(polygons[0][0])) { + polygons.forEach(function (coordinates) { + coordinates.forEach(function (coord) { + if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { + return null; + } + + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + }); + }); + } else { + polygons.forEach(function (coord) { + if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { + return null; + } + + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + }); + } + }); + break; + default: + return null; + } + }); + + // Check if valid bounds found + if (minLat === Number.MAX_VALUE || maxLat === -Number.MAX_VALUE || minLng === Number.MAX_VALUE || maxLng === -Number.MAX_VALUE) { + return null; + } + // Apply buffer to bounds + minLat -= buffer; + maxLat += buffer; + minLng -= buffer; + maxLng += buffer; + + // Set bounds for the Leaflet map + var bounds = [ + [minLat, minLng], + [maxLat, maxLng], + ]; + + return bounds; +}; + +export const filterBoundarySelection = (boundaryData, boundarySelections) => { + if (Object.keys(boundaryData).length === 0 || Object.keys(boundarySelections).length === 0) return []; + let selectionList = []; + Object.values(boundarySelections).forEach((item) => (selectionList = [...selectionList, ...item.map((e) => e.name)])); + let childrenList = []; + const set1 = new Set(selectionList); + selectionList = selectionList.filter((item) => { + const children = findChildren([item], Object.values(boundaryData)?.[0]?.hierarchicalData); + if (children) { + let childrenKeyList = getAllKeys(children); + childrenList = [...childrenList, ...childrenKeyList]; + const nonePresent = childrenKeyList.every((item) => !set1.has(item)); + const allPresent = childrenKeyList.every((item) => set1.has(item)); + return nonePresent ? true : allPresent ? true : false; + } + return true; + }); + return { filteredSelection: selectionList, childrenList }; +}; + +// Recursive function to extract all keys +export const getAllKeys = (obj, keys = []) => { + for (let [key, value] of Object.entries(obj)) { + keys.push(key); + if (value.children) { + getAllKeys(value.children, keys); + } + } + return keys; +}; + +// Remove all layers from the map +export const removeAllLayers = (map, layer) => { + if (!map) return; + layer.forEach((layer) => { + map.removeLayer(layer); + }); +}; +// Map-Marker +export const MapMarker = (style = {}) => { + return L.divIcon({ + className: "custom-svg-icon", + html: PopulationSvg(style), + iconAnchor: [25, 50], + }); +}; +export const DefaultMapMarker = (style = {}) => { + return L.divIcon({ + className: "custom-svg-icon", + html: IconCollection.DefaultMapMarkerSvg(style), + iconAnchor: [25, 50], + }); +}; + +export const disableMapInteractions = (map) => { + if (!map) return; + map.dragging.disable(); + map.scrollWheelZoom.disable(); + map.touchZoom.disable(); + map.doubleClickZoom.disable(); + map.boxZoom.disable(); + map.keyboard.disable(); +}; + +export const enableMapInteractions = (map) => { + if (!map) return; + map.dragging.enable(); + map.scrollWheelZoom.enable(); + map.touchZoom.enable(); + map.doubleClickZoom.enable(); + map.boxZoom.enable(); + map.keyboard.enable(); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js new file mode 100644 index 00000000000..ff5cd55208f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js @@ -0,0 +1,413 @@ +import { EXCEL, GEOJSON, SHAPEFILE, commonColumn } from "../configs/constants"; + +export const calculateAggregateValue = (aggregateName, dataToShow) => { + if (!aggregateName || !dataToShow || dataToShow.length === 0) return; + let aggregateNameList = aggregateName; + if (typeof aggregateName !== "object") aggregateNameList = { name: aggregateName, entities: [aggregateName] }; + let aggregateData = 0; + if (aggregateNameList) + for (const item of aggregateNameList.entities) { + const columnIndex = dataToShow?.[0].indexOf(item); + dataToShow.slice(1).forEach((e) => { + if (e?.[columnIndex]) aggregateData = aggregateData + Number(e[columnIndex]); + }); + } + return aggregateData; +}; + +export const fetchMicroplanData = (microplanData, campaignType, validationSchemas) => { + if (!microplanData) return []; + + let combinesDataList = []; + // Check if microplanData and its upload property exist + if (microplanData?.upload) { + let files = microplanData?.upload; + // Loop through each file in the microplan upload + for (let fileData of files) { + const schema = getSchema(campaignType, fileData.fileType, fileData.templateIdentifier, validationSchemas); + + // Check if the file is not part of boundary or layer data origins + if (!fileData.active || !fileData.fileType || !fileData?.section) continue; // Skip files with errors or missing properties + + // Check if file contains latitude and longitude columns + if (fileData?.data) { + // Check file type and update data availability accordingly + switch (fileData?.fileType) { + case EXCEL: { + // extract dada + const mergedData = schema?.template?.hierarchyLevelWiseSheets ? Object.values(fileData?.data).flat() : Object.values(fileData?.data)?.[0]; + + let commonColumnIndex = mergedData?.[0]?.indexOf(commonColumn); + + let uniqueEntries; + if (commonColumnIndex !== undefined) + uniqueEntries = schema?.template?.hierarchyLevelWiseSheets + ? Array.from(new Map(mergedData.map((entry) => [entry[commonColumnIndex], entry])).values()) + : mergedData; + if (uniqueEntries) combinesDataList.push(uniqueEntries); + break; + } + case GEOJSON: + case SHAPEFILE: { + // Extract keys from the first feature's properties + let keys = Object.keys(fileData?.data.features[0].properties); + + // Extract corresponding values for each feature + const values = fileData?.data?.features.map((feature) => { + // list with features added to it + const temp = keys.map((key) => { + // if (feature.properties[key] === "") { + // return null; + // } + return feature.properties[key]; + }); + return temp; + }); + + let data = [keys, ...values]; + combinesDataList.push(data); + } + } + } + } + } + return combinesDataList; +}; + +// get schema for validation +export const getSchema = (campaignType, type, section, schemas) => { + return schemas.find((schema) => + schema.campaignType + ? schema.campaignType === campaignType && schema.type === type && schema.section === section + : schema.type === type && schema.section === section + ); +}; + +export const fetchMicroplanPreviewData = (campaignType, microplanData, validationSchemas, hierarchy) => { + try { + const filteredSchemaColumns = getFilteredSchemaColumnsList(campaignType, microplanData, validationSchemas, hierarchy); + const fetchedData = fetchMicroplanData(microplanData, campaignType, validationSchemas); + const dataAfterJoins = performDataJoins(fetchedData, filteredSchemaColumns); + return dataAfterJoins; + } catch (error) { + console.error("Error in fetch microplan data: ", error.message); + } +}; + +const getFilteredSchemaColumnsList = (campaignType, microplanData, validationSchemas, hierarchy) => { + let filteredSchemaColumns = getRequiredColumnsFromSchema(campaignType, microplanData, validationSchemas) || []; + if (hierarchy) { + filteredSchemaColumns = [...hierarchy, commonColumn, ...filteredSchemaColumns.filter((e) => e !== commonColumn)]; + } + return filteredSchemaColumns; +}; + +const performDataJoins = (fetchedData, filteredSchemaColumns) => { + return fetchedData.reduce((accumulator, currentData, index) => { + if (index === 0) { + return innerJoinLists(currentData, null, commonColumn, filteredSchemaColumns); + } + return innerJoinLists(accumulator, currentData, commonColumn, filteredSchemaColumns); + }, null); +}; + +export const filterObjects = (arr1, arr2) => { + if (!arr1 || !arr2) return []; + // Create a new array to store the filtered objects + let filteredArray = []; + + // Iterate through the first array + arr1.forEach((obj1) => { + // Find the corresponding object in the second array + let obj2 = _.cloneDeep(arr2.find((item) => item.key === obj1.key)); + + // If the object with the same key is found in the second array and their values are the same + if (obj2 && obj1.value !== obj2.value) { + // Push the object to the filtered array + obj1.oldValue = obj2.value; + filteredArray.push(obj1); + } + }); + + return filteredArray; +}; + +export const useHypothesis = (tempHypothesisList, hypothesisAssumptionsList) => { + // Handles the change in hypothesis value + const valueChangeHandler = (e, setTempHypothesisList, boundarySelections, setToast, t) => { + // Checks it the boundary filters at at root level ( given constraints ) + if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) + return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); + + // validating user input + if (e?.newValue.includes("+") || e?.newValue.includes("e")) return; + if ((e?.newValue < 0 || e.newValue > 10000000000) && e?.newValue !== "") return; + let value; + const decimalIndex = e.newValue.indexOf("."); + if (decimalIndex !== -1) { + const numDecimals = e.newValue.length - decimalIndex - 1; + if (numDecimals <= 2) { + value = e.newValue; + } else if (numDecimals > 2) { + value = e.newValue.substring(0, decimalIndex + 3); + } + } else value = parseFloat(e.newValue); + value = !isNaN(value) ? value : ""; + + // update the state with user input + let newhypothesisEntityIndex = hypothesisAssumptionsList.findIndex((item) => item?.id === e?.item?.id); + let unprocessedHypothesisList = _.cloneDeep(tempHypothesisList); + if (newhypothesisEntityIndex !== -1) unprocessedHypothesisList[newhypothesisEntityIndex].value = value; + setTempHypothesisList(unprocessedHypothesisList); + }; + + return { + valueChangeHandler, + }; +}; + +const validateRequestBody = (body, state, campaignType, setLoaderActivation, setToast, setCheckDataCompletion, navigationEvent, t) => { + if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) { + setLoaderActivation(false); + if (navigationEvent.name === "next") { + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + }); + setCheckDataCompletion("false"); + } else { + setCheckDataCompletion("perform-action"); + } + return false; + } + return true; +}; + +const handleApiSuccess = (data, updateData, setLoaderActivation, setMicroplanData, status) => { + updateData(); + setLoaderActivation(false); + setMicroplanData((previous) => ({ ...previous, microplanStatus: status })); +}; + +const handleApiError = (error, variables, setLoaderActivation, setToast, status, cancleNavigation, updateData, t) => { + setLoaderActivation(false); + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + }); + if (status === "GENERATED") { + cancleNavigation(); + } else { + updateData(); + } +}; + +const constructRequestBody = (microplanData, operatorsObject, MicroplanName, campaignId, status) => { + const body = Digit.Utils.microplan.mapDataForApi(microplanData, operatorsObject, MicroplanName, campaignId, status); + body.PlanConfiguration["id"] = microplanData?.planConfigurationId; + body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; + return body; +}; + +export const updateHyothesisAPICall = async ( + microplanData, + setMicroplanData, + operatorsObject, + MicroplanName, + campaignId, + UpdateMutate, + setToast, + updateData, + setLoaderActivation, + status, + cancleNavigation, + state, + campaignType, + navigationEvent, + setCheckDataCompletion, + t +) => { + try { + const body = constructRequestBody(microplanData, operatorsObject, MicroplanName, campaignId, status); + const isValid = validateRequestBody(body, state, campaignType, setLoaderActivation, setToast, setCheckDataCompletion, navigationEvent, t); + if (!isValid) return; + + await UpdateMutate(body, { + onSuccess: (data) => handleApiSuccess(data, updateData, setLoaderActivation, setMicroplanData, status), + onError: (error, variables) => handleApiError(error, variables, setLoaderActivation, setToast, status, cancleNavigation, updateData, t), + }); + } catch (error) { + setLoaderActivation(false); + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + }); + } +}; + +// get schema for validation +export const getRequiredColumnsFromSchema = (campaignType, microplanData, schemas) => { + if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; + const sortData = []; + if (microplanData?.upload) { + for (const value of microplanData.upload) { + if (value.active && value?.error === null) { + sortData.push({ section: value.section, fileType: value?.fileType }); + } + } + } + const filteredSchemas = + schemas?.filter((schema) => { + if (schema.campaignType) { + return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); + } + return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); + }) || []; + + let finalData = []; + let tempdata; + + tempdata = filteredSchemas + ?.flatMap((item) => + Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRuleConfigureInputs && value?.toShowInMicroplanPreview) { + acc.push(key); + } + return acc; + }, []) + ) + .filter((item) => !!item); + finalData = [...finalData, ...tempdata]; + + tempdata = filteredSchemas + ?.flatMap((item) => + Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.toShowInMicroplanPreview) acc.push(key); + return acc; + }, []) + ) + .filter((item) => !!item); + finalData = [...finalData, ...tempdata]; + return [...new Set(finalData)]; +}; + +/** + * Combines two datasets based on a common column, duplicating rows from data1 for each matching row in data2. + * The final dataset's columns and their order are determined by listOfColumnsNeededInFinalData. + * If data2 is not provided, rows from data1 are included with null values for missing columns. + */ +export const innerJoinLists = (data1, data2, commonColumnName, listOfColumnsNeededInFinalData) => { + // Error handling: Check if data1 array is provided + if (!Array.isArray(data1)) { + throw new Error("The first data input must be an array."); + } + + // Error handling: Check if common column name is provided + if (typeof commonColumnName !== "string") { + throw new Error("Common column name must be a string."); + } + + // Error handling: Check if listOfColumnsNeededInFinalData is provided and is an array + if (!Array.isArray(listOfColumnsNeededInFinalData)) { + throw new Error("listOfColumnsNeededInFinalData must be an array."); + } + + // Find the index of the common column in the first dataset + const commonColumnIndex1 = data1[0].indexOf(commonColumnName); + + // Error handling: Check if common column exists in the first dataset + if (commonColumnIndex1 === -1) { + throw new Error(`Common column "${commonColumnName}" not found in the first dataset.`); + } + + let commonColumnIndex2 = -1; + const data2Map = new Map(); + if (data2) { + // Find the index of the common column in the second dataset + commonColumnIndex2 = data2[0].indexOf(commonColumnName); + + // Error handling: Check if common column exists in the second dataset + if (commonColumnIndex2 === -1) { + throw new Error(`Common column "${commonColumnName}" not found in the second dataset.`); + } + + // Create a map for the second dataset for quick lookup by the common column value + for (let i = 1; i < data2.length; i++) { + const row = data2[i]; + const commonValue = row[commonColumnIndex2]; + if (!data2Map.has(commonValue)) { + data2Map.set(commonValue, []); + } + data2Map.get(commonValue).push(row); + } + } + + // Determine the headers for the final combined dataset based on listOfColumnsNeededInFinalData + const combinedHeaders = listOfColumnsNeededInFinalData.filter((header) => data1[0].includes(header) || data2?.[0].includes(header)); + + // Combine rows + const combinedData = [combinedHeaders]; + const addedCommonValues = new Set(); + for (let i = 1; i < data1.length; i++) { + const row1 = data1[i]; + const commonValue = row1[commonColumnIndex1]; + const rows2 = data2 ? data2Map.get(commonValue) || [[null]] : [[null]]; // Handle missing common values with a placeholder array of null + + // Check if rows2 is the placeholder array + const isPlaceholderArray = rows2.length === 1 && rows2[0].every((value) => value === null); + + // Create combined rows for each row in data2 + if (isPlaceholderArray) { + // If no corresponding row found in data2, use row from data1 with null values for missing columns + const combinedRow = combinedHeaders.map((header) => { + const index1 = data1[0].indexOf(header); + return index1 !== -1 ? row1[index1] : null; + }); + combinedData.push(combinedRow); + } else { + // If corresponding rows found in data2, combine each row from data2 with row from data1 + rows2.forEach((row2) => { + const combinedRow = combinedHeaders.map((header) => { + const index1 = data1[0].indexOf(header); + const index2 = data2 ? data2[0].indexOf(header) : -1; + return index1 !== -1 ? row1[index1] : index2 !== -1 ? row2[index2] : null; + }); + combinedData.push(combinedRow); + }); + } + addedCommonValues.add(commonValue); + } + // Add rows from data2 that do not have a matching row in data1 + if (data2) { + for (let i = 1; i < data2.length; i++) { + const row2 = data2[i]; + const commonValue = row2[commonColumnIndex2]; + if (!addedCommonValues.has(commonValue)) { + const combinedRow = combinedHeaders.map((header) => { + // const index1 = data1[0].indexOf(header); + const index2 = data2[0].indexOf(header); + return index2 !== -1 ? row2[index2] : null; + }); + combinedData.push(combinedRow); + } + } + } + + return combinedData; +}; + +// function to filter the microplan data with respect to the hierarchy selected by the user +export const filterMicroplanDataToShowWithHierarchySelection = (data, selections, hierarchy, hierarchyIndex = 0) => { + if (!selections || selections?.length === 0) return data; + if (hierarchyIndex >= hierarchy?.length) return data; + const filteredHirarchyLevelList = selections?.[hierarchy?.[hierarchyIndex]]?.map((item) => item?.name); + if (!filteredHirarchyLevelList || filteredHirarchyLevelList?.length === 0) return data; + const columnDataIndexForHierarchyLevel = data?.[0]?.indexOf(hierarchy?.[hierarchyIndex]); + if (columnDataIndexForHierarchyLevel === -1) return data; + const levelFilteredData = data.filter((item, index) => { + if (index === 0) return true; + if (item?.[columnDataIndexForHierarchyLevel] && filteredHirarchyLevelList.includes(item?.[columnDataIndexForHierarchyLevel])) return true; + return false; + }); + return filterMicroplanDataToShowWithHierarchySelection(levelFilteredData, selections, hierarchy, hierarchyIndex + 1); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js new file mode 100644 index 00000000000..09e24a4658e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js @@ -0,0 +1,351 @@ +export const processHierarchyAndData = (hierarchy, allData) => { + const hierarchyLists = {}; + let hierarchicalData = {}; + try { + // Process hierarchy + hierarchy.forEach((item) => { + hierarchyLists[item.boundaryType] = []; + }); + + // Process all sets of data + allData.forEach((data) => { + const dataHierarchicalData = {}; + + // Process data for this set + data.slice(1).forEach((row) => { + // Exclude the header row + let currentNode = dataHierarchicalData; + let parent = null; + hierarchy.forEach((item, index) => { + const boundaryType = item.boundaryType; + const dataIndex = data?.[0].indexOf(boundaryType); + if (dataIndex === -1) return; + const cellValue = row[dataIndex]; + if (!cellValue) return; + // Populate hierarchy lists + if (!hierarchyLists[boundaryType].includes(cellValue) && cellValue !== null && cellValue !== "" && cellValue !== undefined) { + hierarchyLists[boundaryType].push(cellValue); + } + + // Populate hierarchical data + if (!currentNode[cellValue]) { + currentNode[cellValue] = { + name: cellValue, + boundaryType: boundaryType, + children: {}, + data: null, + }; + } + + // Assign row data to the correct hierarchical level + if (cellValue) { + if (index === hierarchy.length - 1) { + currentNode[cellValue].data = createDataObject(data[0], row); + } else if (index + 1 < hierarchy.length) { + let nextHierarchyList = hierarchy.slice(index + 1); + let check = true; + nextHierarchyList.forEach((e) => { + const boundaryType = e.boundaryType; + const dataIndex = data?.[0].indexOf(boundaryType); + if (dataIndex === -1) return; + check = check && !row[dataIndex]; + }); + if (check) currentNode[cellValue].data = createDataObject(data[0], row); + } + } + currentNode = currentNode[cellValue].children; + }); + }); + + // Merge dataHierarchicalData into hierarchicalData + hierarchicalData = mergeHierarchicalData(hierarchicalData, dataHierarchicalData); + }); + + // Remove null element from children of each province + Object.values(hierarchicalData).forEach((country) => { + if (country.children[null]) { + country.data = country.children[null].data; + country.children[null] = undefined; + } + }); + } catch (error) { + console.error("Error in processing hierarchy and uploaded data: ", error.message); + // Return empty objects in case of error + return { hierarchyLists: {}, hierarchicalData: {} }; + } + + return { hierarchyLists, hierarchicalData }; +}; + +// Function to merge two hierarchical data objects +const mergeHierarchicalData = (data1, data2) => { + for (const [key, value] of Object.entries(data2)) { + if (!data1[key]) { + if (!value.data) value.data = {}; + data1[key] = value || {}; + } else { + data1[key].data = value.data; // Merge data + mergeHierarchicalData(data1[key].children, value.children); // Recursively merge children + } + if (data1[key].data?.feature) { + const { feature, ...temp } = value.data ? _.cloneDeep(value.data) : {}; + data1[key].data.feature.properties = { ...data1[key].data?.feature?.properties, ...temp }; + } + } + return data1; +}; + +// Function to create a data object with key-value pairs from headers and row data +const createDataObject = (headers, row) => { + const dataObject = {}; + headers.forEach((header, index) => { + dataObject[header] = row[index]; + }); + return dataObject; +}; + +// Find parent in hierarchy +export const findParent = (name, hierarchy, parent, accumulator = []) => { + if (!name || !hierarchy) return null; + for (let key in hierarchy) { + if (hierarchy[key]?.name == name) { + accumulator.push(parent); + } + if (hierarchy[key]?.children) { + let response = findParent(name, hierarchy[key]?.children, hierarchy[key], accumulator); + if (response) + response.forEach((item) => { + if (!accumulator.includes(item)) { + accumulator.push(item); + } + }); + } else { + return accumulator; + } + } + return accumulator; +}; + +/** + * + * @param {Array of parents} parents + * @param {hierarchycal Object data} hierarchy + * @returns An Array containing all the cummulative children + */ +export const findChildren = (parents, hierarchy) => { + const hierarchyTraveller = (parents, hierarchy, accumulator = {}) => { + let tempData = []; + if (accumulator && Object.keys(accumulator).length !== 0) + tempData = { + ...accumulator, + ...hierarchy.reduce((data, item) => { + if (parents.includes(item?.name) && item?.children) { + for (const key in item.children) { + if (!data[key]) { + data[key] = item.children[key]; + } + } + } + return data; + }, {}), + }; + else + tempData = hierarchy.reduce((data, item) => { + if (parents.includes(item?.name) && item?.children) { + for (const key in item.children) { + if (!data[key]) { + data[key] = item.children[key]; + } + } + } + return data; + }, {}); + for (let parent of hierarchy) { + if (parent?.children) tempData = hierarchyTraveller(parents, Object.values(parent?.children), tempData); + } + return tempData; + }; + return hierarchyTraveller(parents, Object.values(hierarchy), {}); +}; + +// Fetched data from tree +export const fetchDropdownValues = (boundaryData, hierarchy, boundarySelections, changedBoundaryType) => { + if ( + !hierarchy || + !boundaryData || + !boundarySelections || + hierarchy.length === 0 || + Object.keys(hierarchy).length === 0 || + Object.keys(boundaryData).length === 0 + ) + return []; + let TempHierarchy = _.cloneDeep(hierarchy); + if (!boundarySelections || Object.values(boundarySelections)?.every((item) => item?.length === 0)) { + for (let i in TempHierarchy) { + if (i === "0") { + TempHierarchy[0].dropDownOptions = findByBoundaryType( + TempHierarchy?.[0]?.boundaryType, + Object.values(boundaryData)?.[0]?.hierarchicalData + ).map((data, index) => ({ + name: data, + code: data, + boundaryType: TempHierarchy?.[0]?.boundaryType, + parentBoundaryType: undefined, + })); + } else TempHierarchy[i].dropDownOptions = []; + } + } else { + const currentHierarchy = findCurrentFilteredHierarchy(Object.values(boundaryData)?.[0]?.hierarchicalData, boundarySelections, TempHierarchy); + let currentDropdownIndex = 0; + hierarchy.forEach((e, index) => { + if (e && e?.boundaryType == changedBoundaryType) { + // && boundarySelections && boundarySelections[e.boundaryType] && boundarySelections[e.boundaryType].length !== 0) { + currentDropdownIndex = index; + } + }); + Object.entries(boundarySelections)?.forEach(([key, value]) => { + let currentindex = hierarchy.findIndex((e) => e?.boundaryType === key); + if (currentDropdownIndex !== currentindex) return; + let childIndex = hierarchy.findIndex((e) => e?.parentBoundaryType === key); + if (childIndex == -1) return; + if (TempHierarchy?.[childIndex]) { + let newDropDownValuesForChild = []; + for (const element of value) { + let tempStore = Object.values(findChildren([element.name], currentHierarchy)).map((value) => ({ + name: value?.name, + code: value?.name, + parent: element, + boundaryType: TempHierarchy[childIndex]?.boundaryType, + parentBoundaryType: TempHierarchy[childIndex]?.parentBoundaryType, + })); + if (tempStore) newDropDownValuesForChild.push(...tempStore); + } + // if (TempHierarchy[childIndex].dropDownOptions) + // TempHierarchy[childIndex].dropDownOptions = [...TempHierarchy[childIndex].dropDownOptions, ...newDropDownValuesForChild]; + TempHierarchy[childIndex].dropDownOptions = newDropDownValuesForChild; + } + }); + } + return TempHierarchy; +}; + +const findByBoundaryType = (boundaryType, hierarchy) => { + for (let [key, value] of Object.entries(hierarchy)) { + if (value?.boundaryType === boundaryType) return Object.keys(hierarchy).filter(Boolean); + if (value?.children) return findByBoundaryType(boundaryType, value?.children); + return []; + } + return []; +}; + +// makes a tree with the boundary selections as there might be duplicates in different branches that are not yet selected +const findCurrentFilteredHierarchy = (hierarchyTree, boundarySelections, hierarchy) => { + const newtree = constructNewHierarchyTree(hierarchy, hierarchyTree, boundarySelections); + return newtree; +}; + +const constructNewHierarchyTree = (hierarchy, oldTree, boundarySelection, level = 0) => { + // let newTree = { ...oldTree }; // Initialize a new hierarchy tree + let newTree = {}; // Initialize a new hierarchy tree + if (!hierarchy?.[level]) return; + const levelName = hierarchy[level].boundaryType; + + // Get the selections for this level from the boundary selection object + const selections = boundarySelection[levelName] || []; + // If there are selections for this level + if (selections.length > 0) { + // Construct the new hierarchy tree based on selections + for (const selection of selections) { + const { name } = selection; + // If the selection exists in the existing hierarchy tree + if (oldTree[name]) { + // Add the selected division to the new hierarchy tree + newTree[name] = { ...oldTree[name] }; + // If there are children, recursively construct the children + if (oldTree[name].children) { + oldTree[name].children; + const nonNullObject = Object.entries(oldTree[name].children).reduce((acc, [key, value]) => { + if (value.name !== null) { + acc[key] = value; + } + return acc; + }, {}); + newTree[name].children = constructNewHierarchyTree(hierarchy, nonNullObject, boundarySelection, level + 1); + } + } + } + } else { + const nonNullObject = Object.entries(oldTree).reduce((acc, [key, value]) => { + if (value.name !== null) { + acc[key] = value; + } + return acc; + }, {}); + newTree = nonNullObject; + } + + return newTree; +}; + +// Recursively calculates aggregate values for numerical properties within the `data` objects of each node in a hierarchical tree structure. +// Updates the `properties` object within the `feature` object of each node with the aggregate values, if present. +export const calculateAggregateForTree = (tree) => { + try { + function calculateAggregate(node) { + if (!node.children || Object.keys(node.children).length === 0) { + // if the node has no children, return a new node with its own data + return { ...node, data: { ...node.data } }; + } + + // Recursively calculate aggregate values for each child + const newChildren = {}; + + for (const childKey in node.children) { + const child = node.children[childKey]; + const newChild = calculateAggregate(child); + newChildren[childKey] = newChild; + } + + // Aggregate numerical values dynamically + const aggregate = {}; + for (const childKey in newChildren) { + const child = newChildren[childKey]; + for (const prop in child.data) { + if (typeof child.data[prop] === "number") { + aggregate[prop] = (aggregate[prop] || 0) + child.data[prop]; + } + } + } + + // Create a new node with updated data + const newNode = { + ...node, + data: { ...node.data, ...aggregate }, + children: newChildren, + }; + + // Update properties in the feature object + if (newNode.data.feature) { + newNode.data.feature.properties = { ...newNode.data.feature.properties, ...aggregate }; + } + + return newNode; + } + + const newTree = {}; + + // Iterate over each node object + for (const nodeKey in tree) { + const node = tree[nodeKey]; + // Calculate aggregate values for the current node + const newNode = calculateAggregate(node); + // Add the updated node to the new tree + newTree[nodeKey] = newNode; + } + + return newTree; + } catch (error) { + console.error("Failed to calculate treenode aggregates"); + return {}; + } +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js new file mode 100644 index 00000000000..129ec488b43 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js @@ -0,0 +1,486 @@ +import { Request } from "@egovernments/digit-ui-libraries"; +import { parseXlsxToJsonMultipleSheetsForSessionUtil } from "../utils/exceltojson"; +import JSZip from "jszip"; +import * as XLSX from "xlsx"; +import axios from "axios"; +import shp from "shpjs"; +import { EXCEL, GEOJSON, SHAPEFILE, ACCEPT_HEADERS, LOCALITY, commonColumn } from "../configs/constants"; +import { addBoundaryData, fetchBoundaryData, filterBoundaries } from "./createTemplate"; +import { handleExcelFile } from "./uploadUtils"; + +function handleExcelArrayBuffer(arrayBuffer, file) { + return new Promise((resolve, reject) => { + try { + // Read the response as an array buffer + // const arrayBuffer = response.arrayBuffer(); + + // Convert the array buffer to binary string + const data = new Uint8Array(arrayBuffer); + const binaryString = String.fromCharCode.apply(null, data); + + // Parse the binary string into a workbook + const workbook = XLSX.read(binaryString, { type: "binary" }); + + // Assuming there's only one sheet in the workbook + const sheetName = workbook.SheetNames[0]; + const sheet = workbook.Sheets[sheetName]; + + // Convert the sheet to JSON object + const jsonData = XLSX.utils.sheet_to_json(sheet); + + resolve(jsonData); + } catch (error) { + reject(error); + } + }); +} + +function shpToGeoJSON(shpBuffer, file) { + return new Promise((resolve, reject) => { + try { + shp(shpBuffer) + .then((geojson) => { + resolve({ jsonData: geojson, file }); + }) + .catch((error) => reject(error)); + } catch (error) { + reject(error); + } + }); +} + +function parseGeoJSONResponse(arrayBuffer, file) { + return new Promise((resolve, reject) => { + try { + const decoder = new TextDecoder("utf-8"); + const jsonString = decoder.decode(arrayBuffer); + const jsonData = JSON.parse(jsonString); + resolve({ jsonData, file }); + } catch (error) { + reject(error); + } + }); +} + +// Function to read blob data and parse it into JSON +function parseBlobToJSON(blob, file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.onload = function (event) { + const data = new Uint8Array(event.target.result); + const workbook = XLSX.read(data, { type: "array" }); + const jsonData = {}; + + workbook.SheetNames.forEach((sheetName) => { + const sheetData = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]); + jsonData[sheetName] = sheetData; + }); + + resolve({ jsonData, file }); + }; + + reader.onerror = function () { + reject(new Error("Error reading the blob data")); + }; + + reader.readAsArrayBuffer(blob); + }); +} + +export const updateSessionUtils = { + computeSessionObject: async (row, state, additionalProps) => { + const sessionObj = {}; + const setCurrentPage = () => { + sessionObj.currentPage = { + id: 0, + name: "MICROPLAN_DETAILS", + component: "MicroplanDetails", + checkForCompleteness: true, + }; + }; + + //currently hardcoded + const setMicroplanStatus = () => { + sessionObj.status = { + MICROPLAN_DETAILS: true, + UPLOAD_DATA: true, + HYPOTHESIS: true, + FORMULA_CONFIGURATION: true, + }; + }; + + const setMicroplanDetails = () => { + if (row.name) { + sessionObj.microplanDetails = { + name: row?.name, + }; + } + }; + + const setMicroplanHypothesis = () => { + if (row.assumptions.length > 0) { + sessionObj.hypothesis = row.assumptions?.filter((item) => item?.active); + } + }; + + const sortRules = (rules) => { + // Step 1: Identify all unique rule outputs + const allOutputs = [...new Set(rules.map((rule) => rule.output))]; + + // Step 2: Build input-output relationships + const inputOutputMap = new Map(); // Map to store input -> output relationship + rules.forEach((rule) => { + const { input, output } = rule; + if (!inputOutputMap.has(input)) { + inputOutputMap.set(input, []); + } + inputOutputMap.get(input).push(output); + }); + + // Step 3: Sort the output list based on dependencies + const sortedOutputList = []; + const visited = new Set(); + + const dfs = (output) => { + if (!visited.has(output)) { + visited.add(output); + if (inputOutputMap.has(output)) { + inputOutputMap.get(output).forEach((input) => { + dfs(input); + }); + } + sortedOutputList.push(output); + } + }; + + // Sort outputs based on dependencies + allOutputs.forEach((output) => { + dfs(output); + }); + + // Reverse to get outputs in the correct order (outputs first) + sortedOutputList.reverse(); + + // Step 4: Arrange rules based on sorted output list + const sortedRules = []; + const ruleMap = new Map(rules.map((rule) => [rule.id, rule])); + + sortedOutputList.forEach((output) => { + rules + .filter((rule) => rule.output === output) + .forEach((rule) => { + sortedRules.push(rule); + }); + }); + + return sortedRules; + }; + + const setMicroplanRuleEngine = () => { + const rulesList = state.UIConfiguration?.filter((item) => item.name === "ruleConfigure")?.[0]?.ruleConfigureOperators; + let sortedRules = sortRules(row.operations); + if (row.operations.length > 0) { + sessionObj.ruleEngine = sortedRules?.map((item) => { + return { + ...item, + operator: rulesList.filter((rule) => rule.code === item.operator)?.[0]?.name, + }; + }); + } + }; + + const setDraftValues = () => { + sessionObj.planConfigurationId = row?.id; + sessionObj.auditDetails = row.auditDetails; + }; + + const fetchBoundaryDataWrapper = async (schemaData) => { + let boundaryDataAgainstBoundaryCode = {}; + // if (!schemaData?.doHierarchyCheckInUploadedData) { + try { + const rootBoundary = additionalProps.campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable + const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; + let boundaryData = sessionData.filteredBoundaries; + let filteredBoundaries; + if (!boundaryData) { + // Only fetch boundary data if not present in session storage + boundaryData = await fetchBoundaryData( + await Digit.ULBService.getCurrentTenantId(), + additionalProps.campaignData?.hierarchyType, + rootBoundary?.[0]?.code + ); + filteredBoundaries = await filterBoundaries(boundaryData, additionalProps.campaignData?.boundaries); + + // Update the session storage with the new filtered boundaries + Digit.SessionStorage.set("microplanHelperData", { + ...sessionData, + filteredBoundaries: filteredBoundaries, + }); + } else { + filteredBoundaries = boundaryData; + } + const xlsxData = addBoundaryData([], filteredBoundaries, additionalProps.campaignData?.hierarchyType)?.[0]?.data; + xlsxData.forEach((item, i) => { + if (i === 0) return; + let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn); + if (boundaryCodeIndex >= item.length) { + // If boundaryCodeIndex is out of bounds, return the item as is + boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(additionalProps.t); + } else { + // Otherwise, remove the element at boundaryCodeIndex + boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item + .slice(0, boundaryCodeIndex) + .concat(item.slice(boundaryCodeIndex + 1)) + .map(additionalProps.t); + } + }); + } catch (error) { + console.error(error?.message); + } + // } + return boundaryDataAgainstBoundaryCode; + }; + + const handleGeoJson = async (file, result, upload, translatedData, active, processedData, shapefileOrigin = false) => { + if (!file) { + console.error(`${shapefileOrigin ? "Shapefile" : "Geojson"} file is undefined`); + return upload; + } + + const { inputFileType, templateIdentifier, filestoreId, id: fileId } = file || {}; + let uploadObject = createUploadObject(templateIdentifier, inputFileType, fileId, filestoreId, shapefileOrigin ? ".zip" : ".geojson", active); + + const schema = findSchema(inputFileType, templateIdentifier, additionalProps?.campaignType); + if (!schema) { + console.error("Schema got undefined while handling geojson at handleGeoJson"); + return [...upload, uploadObject]; + } + + await handleGeoJsonSpecific(schema, uploadObject, templateIdentifier, result, translatedData, filestoreId, processedData); + upload.push(uploadObject); + return upload; + }; + + const handleExcel = (file, result, upload, translatedData, active) => { + if (!file) { + console.error("Excel file is undefined"); + return upload; + } + + const { inputFileType, templateIdentifier, filestoreId, id: fileId } = file || {}; + let uploadObject = createUploadObject(templateIdentifier, inputFileType, fileId, filestoreId, ".xlsx", active), + schema = findSchema(inputFileType, templateIdentifier, additionalProps.campaignType); + if (!schema) { + console.error("Schema got undefined while handling excel at handleExcel"); + return [...upload, uploadObject]; + } + + uploadObject.data = result; //resultAfterMapping?.tempFileDataToStore; + upload.push(uploadObject); + return upload; + }; + + const createUploadObject = (templateIdentifier, inputFileType, fileId, filestoreId, extension, active) => ({ + id: fileId, + templateIdentifier, + section: templateIdentifier, + fileName: `${templateIdentifier}${extension}`, + fileType: inputFileType, + file: null, + fileId: fileId, + filestoreId: filestoreId, + error: null, + resourceMapping: row?.resourceMapping?.filter((resourse) => resourse.filestoreId === filestoreId).map((item) => ({ ...item, filestoreId })), + data: {}, + active, + }); + + const findSchema = (inputFileType, templateIdentifier, campaignType) => { + return state?.Schemas?.find( + (schema) => + schema.type === inputFileType && schema.section === templateIdentifier && (!schema.campaignType || schema.campaignType === campaignType) + ); + }; + + const handleGeoJsonSpecific = async (schema, upload, templateIdentifier, result, translatedData, filestoreId, processedData) => { + let schemaKeys; + if (schema?.schema?.["Properties"]) { + schemaKeys = additionalProps.hierarchyData?.concat(Object.keys(schema.schema["Properties"])); + } + upload.data = result; + if (processedData) return; + const mappedToList = upload?.resourceMapping.map((item) => item.mappedTo); + let sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, upload?.resourceMapping); + const newFeatures = result["features"].map((item) => { + let newProperties = {}; + sortedSecondList + ?.filter((resourse) => resourse.filestoreId === filestoreId) + .forEach((e) => { + newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; + }); + item["properties"] = newProperties; + return item; + }); + upload.data.features = newFeatures; + if ( + additionalProps.hierarchyData?.every( + (item) => + !mappedToList.includes(`${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`) + ) + ) { + let boundaryDataAgainstBoundaryCode = await fetchBoundaryDataWrapper(schema); + upload.data.features.forEach((feature) => { + const boundaryCode = feature.properties.boundaryCode; + let additionalDetails = {}; + for (let i = 0; i < additionalProps.hierarchyData?.length; i++) { + if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { + additionalDetails[additionalProps.hierarchyData?.[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; + } else { + additionalDetails[additionalProps.hierarchyData?.[i]] = ""; + } + } + feature.properties = { ...additionalDetails, ...feature.properties }; + }); + } + }; + + const fetchFiles = async () => { + const files = row?.files; + if (!files || files.length === 0) { + return []; + } + + const promises = []; + let storedData = []; + for (const { filestoreId, inputFileType, templateIdentifier, id, active } of files) { + if (!active) continue; + const schemaData = findSchema(inputFileType, templateIdentifier, additionalProps?.campaignType); + if (!schemaData) { + console.error("Schema got undefined while handling geojson at handleGeoJson"); + return [...upload, uploadObject]; + } + const boundaryDataAgainstBoundaryCode = {}; + let fileData = { + filestoreId, + inputFileType, + templateIdentifier, + id, + }; + let dataInSsn = Digit.SessionStorage.get("microplanData")?.upload?.find((item) => item.active && item.id === id); + if (dataInSsn && dataInSsn.filestoreId === filestoreId) { + storedData.push({ file: fileData, jsonData: dataInSsn?.data, processedData: true, translatedData: false, active }); + } else { + const promiseToAttach = axios + .get("/filestore/v1/files/id", { + responseType: "arraybuffer", + headers: { + "Content-Type": "application/json", + Accept: ACCEPT_HEADERS[inputFileType], + "auth-token": Digit.UserService.getUser()?.["access_token"], + }, + params: { + tenantId: Digit.ULBService.getCurrentTenantId(), + fileStoreId: filestoreId, + }, + }) + .then(async (res) => { + if (inputFileType === EXCEL) { + try { + const file = new Blob([res.data], { type: ACCEPT_HEADERS[inputFileType] }); + const response = await handleExcelFile( + file, + schemaData, + additionalProps.hierarchyData.map( + (item) => `${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}` + ), + { id: inputFileType }, + boundaryDataAgainstBoundaryCode, + () => {}, + additionalProps.t, + additionalProps.campaignData, + additionalProps.readMeSheetName + ); + let fileData = { + filestoreId, + inputFileType, + templateIdentifier, + id, + }; + + return { jsonData: response.fileDataToStore, file: fileData, translatedData: true, active }; + } catch (error) { + console.error(error); + } + } else if (inputFileType === GEOJSON) { + let response = await parseGeoJSONResponse(res.data, { + filestoreId, + inputFileType, + templateIdentifier, + id, + }); + return { ...response, translatedData: true, active }; + } else if (inputFileType === SHAPEFILE) { + const geoJson = await shpToGeoJSON(res.data, { + filestoreId, + inputFileType, + templateIdentifier, + id, + }); + return { ...geoJson, translatedData: true, active }; + } + }); + promises.push(promiseToAttach); + } + } + + const resolvedPromises = await Promise.all(promises); + let result = storedData; + if (resolvedPromises) result = [...storedData, ...resolvedPromises]; + return result; + }; + const setMicroplanUpload = async (filesResponse) => { + //here based on files response set data in session + if (filesResponse.length === 0) { + return {}; + } + //populate this object based on the files and return + let upload = []; + + await filesResponse.forEach(async ({ jsonData, file, translatedData, active, processedData }, idx) => { + switch (file?.inputFileType) { + case "Shapefile": + upload = await handleGeoJson(file, jsonData, upload, translatedData, active, processedData, true); + break; + case "Excel": + upload = handleExcel(file, jsonData, upload, translatedData, active); + break; + case "GeoJSON": + upload = await handleGeoJson(file, jsonData, upload, translatedData, active, processedData); + break; + default: + break; + } + }); + //here basically parse the files data from filestore parse it and populate upload object based on file type -> excel,shape,geojson + return upload; + }; + + try { + setCurrentPage(); + setMicroplanStatus(); + setMicroplanDetails(); + setMicroplanHypothesis(); + setMicroplanRuleEngine(); + setDraftValues(); + // calling fucntion to cache filtered boundary data + await fetchBoundaryDataWrapper({}); + const filesResponse = await fetchFiles(); + const upload = await setMicroplanUpload(filesResponse); + sessionObj.upload = upload; + return sessionObj; + } catch (error) { + console.error(error.message); + } + }, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js new file mode 100644 index 00000000000..066f47c47f3 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js @@ -0,0 +1,880 @@ +import ExcelJS from "exceljs"; +import { + freezeSheetValues, + freezeWorkbookValues, + hideUniqueIdentifierColumn, + performUnfreezeCells, + unfreezeColumnsByHeader, + updateFontNameToRoboto, +} from "../utils/excelUtils"; +import { addBoundaryData, createTemplate, fetchBoundaryData, filterBoundaries } from "../utils/createTemplate"; +import { BOUNDARY_DATA_SHEET, EXCEL, FACILITY_DATA_SHEET, SCHEMA_PROPERTIES_PREFIX, SHEET_COLUMN_WIDTH, commonColumn } from "../configs/constants"; +import shp from "shpjs"; +import JSZip from "jszip"; +import { checkForErrorInUploadedFileExcel } from "../utils/excelValidations"; +import { convertJsonToXlsx } from "../utils/jsonToExcelBlob"; +import { parseXlsxToJsonMultipleSheets } from "../utils/exceltojson"; +import { geojsonValidations } from "../utils/geojsonValidations"; + +// Function for checking the uploaded file for nameing conventions +export const validateNamingConvention = (file, namingConvention, setToast, t) => { + try { + let processedConvention = namingConvention.replace("$", ".[^.]*$"); + const regx = new RegExp(processedConvention); + + if (regx && !regx.test(file.name)) { + setToast({ + state: "error", + message: t("ERROR_NAMING_CONVENSION"), + }); + return false; + } + return true; + } catch (error) { + console.error(error.message); + setToast({ + state: "error", + message: t("ERROR_UNKNOWN"), + }); + } +}; + +// Function for reading ancd checking geojson data +export const readGeojson = async (file, t) => { + return new Promise((resolve, reject) => { + if (!file) return resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); + + const reader = new FileReader(); + reader.onload = (e) => { + try { + const geoJSONData = JSON.parse(e.target.result); + const trimmedGeoJSONData = trimJSON(geoJSONData); + resolve({ valid: true, geojsonData: trimmedGeoJSONData }); + } catch (error) { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_INCORRECT_FORMAT") } }); + } + }; + reader.onerror = (error) => { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") } }); + }; + + reader.readAsText(file); + }); +}; + +// Function to recursively trim leading and trailing spaces from string values in a JSON object +export const trimJSON = (jsonObject) => { + if (typeof jsonObject !== "object") { + return jsonObject; // If not an object, return as is + } + + if (Array.isArray(jsonObject)) { + return jsonObject.map((item) => trimJSON(item)); // If it's an array, recursively trim each item + } + + const trimmedObject = {}; + for (const key in jsonObject) { + if (Object.hasOwn(jsonObject, key)) { + const value = jsonObject[key]; + // Trim string values, recursively trim objects + trimmedObject[key.trim()] = typeof value === "string" ? value.trim() : typeof value === "object" ? trimJSON(value) : value; + } + } + return trimmedObject; +}; +// Function for reading and validating shape file data +export const readAndValidateShapeFiles = async (file, t, namingConvention) => { + return new Promise((resolve, reject) => { + const readAndValidate = async () => { + if (!file) { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); + } + const fileRegex = new RegExp(namingConvention.replace("$", ".*$")); + // File Size Check + const fileSizeInBytes = file.size; + const maxSizeInBytes = 2 * 1024 * 1024 * 1024; // 2 GB + + // Check if file size is within limit + if (fileSizeInBytes > maxSizeInBytes) + resolve({ valid: false, message: t("ERROR_FILE_SIZE"), toast: { state: "error", message: t("ERROR_FILE_SIZE") } }); + + try { + const zip = await JSZip.loadAsync(file); + const isEPSG4326 = await checkProjection(zip); + if (!isEPSG4326) { + resolve({ valid: false, message: t("ERROR_WRONG_PRJ"), toast: { state: "error", message: t("ERROR_WRONG_PRJ") } }); + } + const files = Object.keys(zip.files); + const allFilesMatchRegex = files.every((fl) => { + return fileRegex.test(fl); + }); + let regx = new RegExp(namingConvention.replace("$", "\\.shp$")); + const shpFile = zip.file(regx)[0]; + regx = new RegExp(namingConvention.replace("$", "\\.shx$")); + const shxFile = zip.file(regx)[0]; + regx = new RegExp(namingConvention.replace("$", "\\.dbf$")); + const dbfFile = zip.file(regx)[0]; + + let geojson; + if (shpFile && dbfFile) { + const shpArrayBuffer = await shpFile.async("arraybuffer"); + const dbfArrayBuffer = await dbfFile.async("arraybuffer"); + + geojson = shp.combine([shp.parseShp(shpArrayBuffer), shp.parseDbf(dbfArrayBuffer)]); + } + if (shpFile && dbfFile && shxFile && allFilesMatchRegex) resolve({ valid: true, data: geojson }); + else if (!allFilesMatchRegex) + resolve({ + valid: false, + message: [t("ERROR_CONTENT_NAMING_CONVENSION")], + toast: { state: "error", data: geojson, message: t("ERROR_CONTENT_NAMING_CONVENSION") }, + }); + else if (!shpFile) + resolve({ valid: false, message: [t("ERROR_SHP_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHP_MISSING") } }); + else if (!dbfFile) + resolve({ valid: false, message: [t("ERROR_DBF_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_DBF_MISSING") } }); + else if (!shxFile) + resolve({ valid: false, message: [t("ERROR_SHX_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHX_MISSING") } }); + } catch (error) { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); + } + }; + readAndValidate(); + }); +}; + +// Function for projections check in case of shapefile data +export const checkProjection = async (zip) => { + const prjFile = zip.file(/.prj$/i)[0]; + if (!prjFile) { + return "absent"; + } + + const prjText = await prjFile.async("text"); + + if (prjText.includes("GEOGCS") && prjText.includes("WGS_1984") && prjText.includes("DATUM") && prjText.includes("D_WGS_1984")) { + return "EPSG:4326"; + } + return false; +}; + +// find readMe as per campaign, template identifier and file type +export const findReadMe = (readMeCollection, campaignType, type, section) => { + if (!readMeCollection) return readMeCollection; + return ( + readMeCollection.find( + (readMe) => readMe.fileType === type && readMe.templateIdentifier === section && (!readMe.campaignType || readMe.campaignType === campaignType) + )?.data || {} + ); +}; + +// Function to handle the template download +export const downloadTemplate = async ({ + campaignType, + type, + section, + setToast, + campaignData, + hierarchyType, + Schemas, + HierarchyConfigurations, + setLoader, + hierarchy, + readMeData, + readMeSheetName, + t, +}) => { + try { + setLoader("LOADING"); + await delay(100); + // Find the template based on the provided parameters + const schema = getSchema(campaignType, type, section, Schemas); + const hierarchyLevelName = HierarchyConfigurations?.find((item) => item.name === "devideBoundaryDataBy")?.value; + const filteredReadMeData = findReadMe(readMeData, campaignType, type, section); + let template = await createTemplate({ + hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, + hierarchyLevelName, + addFacilityData: schema?.template?.includeFacilityData, + schema, + boundaries: campaignData?.boundaries, + tenantId: Digit.ULBService.getCurrentTenantId(), + hierarchyType, + readMeData: filteredReadMeData, + readMeSheetName, + t, + }); + const translatedTemplate = translateTemplate(template, t); + + // Create a new workbook + const workbook = new ExcelJS.Workbook(); + + formatTemplate(translatedTemplate, workbook); + + // Color headers + colorHeaders( + workbook, + [...hierarchy.map((item) => t(item)), t(commonColumn)], + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], + [] + ); + + formatAndColorReadMeFile( + workbook, + filteredReadMeData?.map((item) => item?.header), + readMeSheetName + ); + + // protextData + await protectData({ + workbook, + hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, + addFacilityData: schema?.template?.includeFacilityData, + schema, + t, + }); + + // Write the workbook to a buffer + workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { + // Create a Blob from the buffer + const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); + // Create a URL for the Blob + const url = URL.createObjectURL(blob); + // Create a link element and simulate click to trigger download + const link = document.createElement("a"); + link.href = url; + link.download = `${t(section)}.xlsx`; + link.click(); + // Revoke the URL to release the Blob + URL.revokeObjectURL(url); + setLoader(false); + }); + } catch (error) { + setLoader(false); + console.error(error?.message); + setToast({ state: "error", message: t("ERROR_DOWNLOADING_TEMPLATE") }); + } +}; + +export const formatAndColorReadMeFile = (workbook, headerSet, readMeSheetName) => { + const readMeSheet = workbook.getWorksheet(readMeSheetName); + if (!readMeSheet) return; + setAndFormatHeaders(readMeSheet); + formatWorksheet(readMeSheet, headerSet); +}; + +export function setAndFormatHeaders(worksheet) { + const row = worksheet.getRow(1); + // Color the header cell + row.eachCell((cell) => { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "f25449" }, // Header cell color + }; + cell.alignment = { vertical: "middle", horizontal: "center", wrapText: true }; // Center align and wrap text + cell.font = { bold: true }; + }); +} +export function formatWorksheet(worksheet, headerSet) { + // Add the data rows with text wrapping + const lineHeight = 15; // Set an approximate line height + const maxCharactersPerLine = 100; // Set a maximum number of characters per line for wrapping + + worksheet.eachRow((row) => { + row.eachCell({ includeEmpty: true }, (cell) => { + cell.alignment = { vertical: "middle", horizontal: "left", wrapText: true }; // Apply text wrapping + // Calculate the required row height based on content length + const numberOfLines = Math.ceil(cell?.value.length / maxCharactersPerLine); + row.height = numberOfLines * lineHeight; + + // Make the header text bold + if (headerSet?.includes(cell.value)) { + cell.font = { bold: true }; + } + }); + }); + worksheet.getColumn(1).width = 130; +} + +export const protectData = async ({ workbook, hierarchyLevelWiseSheets = true, addFacilityData = false, schema, t }) => { + if (hierarchyLevelWiseSheets) { + if (addFacilityData) { + await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); + await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); + if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { + let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); + await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); + } + if (schema?.template?.facilitySchemaApiMapping) { + } else { + } + } else { + await freezeWorkbookValues(workbook); + await unfreezeColumnsByHeader( + workbook, + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] + ); + } + } else { + // total boundary Data in one sheet + if (addFacilityData) { + await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); + await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); + if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { + let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); + await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); + } + + if (schema?.template?.facilitySchemaApiMapping) { + } else { + } + } else { + await freezeWorkbookValues(workbook); + await unfreezeColumnsByHeader( + workbook, + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] + ); + } + } +}; + +export const colorHeaders = async (workbook, headerList1, headerList2, headerList3) => { + try { + // Iterate through each sheet + workbook.eachSheet((sheet, sheetId) => { + // Get the first row + const firstRow = sheet.getRow(1); + + // Iterate through each cell in the first row + firstRow.eachCell((cell, colNumber) => { + const cellValue = cell.value.toString(); + + // Check conditions and set colors + if (headerList1?.includes(cellValue)) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "ff9248" }, + }; + } else if (headerList2?.includes(cellValue)) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "93C47D" }, + }; + } else if (headerList3?.includes(cellValue)) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + } + }); + }); + } catch (error) { + console.error("Error coloring headers:", error); + } +}; + +export const formatTemplate = (template, workbook) => { + template.forEach(({ sheetName, data }) => { + // Create a new worksheet with properties + const worksheet = workbook.addWorksheet(sheetName); + data?.forEach((row, index) => { + const worksheetRow = worksheet.addRow(row); + + // Apply fill color to each cell in the first row and make cells bold + if (index === 0) { + worksheetRow.eachCell((cell, colNumber) => { + // Set font to bold + cell.font = { bold: true }; + + // Enable text wrapping + cell.alignment = { wrapText: true }; + // Update column width based on the length of the cell's text + const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width + const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding + worksheet.getColumn(colNumber).width = newWidth; + }); + } + }); + updateFontNameToRoboto(worksheet); + }); +}; + +export const translateTemplate = (template, t) => { + // Initialize an array to hold the transformed result + const transformedResult = []; + + // Iterate over each sheet in the divided data + for (const sheet of template) { + const sheetData = sheet.data; + + // Find the index of the boundaryCode column in the header row + const boundaryCodeIndex = sheetData[0].indexOf(commonColumn); + + const sheetName = t(sheet.sheetName); + const transformedSheet = { + sheetName: sheetName.length > 31 ? sheetName.slice(0, 31) : sheetName, + data: [], + }; + + // Iterate over each row in the sheet data + for (const [rowIndex, row] of sheetData.entries()) { + // Transform each entity in the row using the transformFunction + const transformedRow = row.map((entity, index) => { + // Skip transformation for the boundaryCode column + if ((index === boundaryCodeIndex && rowIndex !== 0) || typeof entity === "number") { + return entity; + } + return t(entity); + }); + transformedSheet.data.push(transformedRow); + } + + // Add the transformed sheet to the transformed result + transformedResult.push(transformedSheet); + } + + return transformedResult; +}; + +// get schema for validation +export const getSchema = (campaignType, type, section, schemas) => { + return schemas.find((schema) => { + if (!schema.campaignType) { + return schema.type === type && schema.section === section; + } + return schema.campaignType === campaignType && schema.type === type && schema.section === section; + }); +}; + +// Performs resource mapping and data filtering for Excel files based on provided schema data, hierarchy, and file data. +export const resourceMappingAndDataFilteringForExcelFiles = (schemaData, hierarchy, selectedFileType, fileDataToStore, t) => { + const resourceMappingData = []; + const newFileData = {}; + if (selectedFileType.id === EXCEL && fileDataToStore) { + // Extract all unique column names from fileDataToStore and then doing thir resource mapping + const columnForMapping = new Set(Object.values(fileDataToStore).flatMap((value) => value?.[0] || [])); + if (schemaData?.schema?.["Properties"]) { + const schemaKeys = Object.keys(schemaData.schema["Properties"]) + .map((item) => generateLocalisationKeyForSchemaProperties(item)) + .concat([...hierarchy, commonColumn]); + schemaKeys.forEach((item) => { + if (columnForMapping.has(t(item))) { + resourceMappingData.push({ + mappedFrom: t(item), + mappedTo: revertLocalisationKey(item), + }); + } + }); + } + + // Filtering the columns with respect to the resource mapping and removing the columns that are not needed + Object.entries(fileDataToStore).forEach(([key, value]) => { + const data = []; + const headers = []; + const toRemove = []; + if (value && value.length > 0) { + value[0].forEach((item, index) => { + const mappedTo = resourceMappingData.find((e) => e.mappedFrom === item)?.mappedTo; + if (!mappedTo) { + toRemove.push(index); + return; + } + headers.push(mappedTo); + return; + }); + for (let i = 1; i < value?.length; i++) { + let temp = []; + for (let j = 0; j < value[i].length; j++) { + if (!toRemove.includes(j)) { + temp.push(value[i][j]); + } + } + data.push(temp); + } + } + newFileData[key] = [headers, ...data]; + }); + } + return { tempResourceMappingData: resourceMappingData, tempFileDataToStore: newFileData }; +}; +export const revertLocalisationKey = (localisedCode) => { + if (!localisedCode || !localisedCode.startsWith(SCHEMA_PROPERTIES_PREFIX + "_")) { + return localisedCode; + } + return localisedCode.substring(SCHEMA_PROPERTIES_PREFIX.length + 1); +}; +export const prepareExcelFileBlobWithErrors = async (data, errors, schema, hierarchy, readMeData, readMeSheetName, t) => { + let tempData = [...data]; + // Process each dataset within the data object + const processedData = {}; + const schemaCols = schema?.schema?.Properties ? Object.keys(schema.schema.Properties) : []; + for (const sheet of tempData) { + const dataset = [...sheet.data]; + + // Add the 'error' column to the header + dataset[0] = dataset[0].map((item) => { + if (item !== commonColumn && schemaCols.includes(item)) { + return t(generateLocalisationKeyForSchemaProperties(item)); + } + return t(item); + }); + if (sheet.sheetName !== t(BOUNDARY_DATA_SHEET) && sheet.sheetName !== t(readMeSheetName)) { + // Process each data row + if (errors) { + dataset[0].push(t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN")); + let headerCount = 0; + for (let i = 1; i < dataset.length; i++) { + const row = dataset[i]; + if (i === 1 && row) { + headerCount = row.length; + } + + if (headerCount > row.length) { + row.push(...Array(headerCount - row.length).fill("")); + } + + // Check if there are errors for the given commonColumnData + const errorInfo = errors?.[sheet.sheetName]?.[i - 1]; + if (errorInfo) { + let rowDataAddOn = Object.entries(errorInfo) + .map(([key, value]) => { + return `${t(key)}: ${value.map((item) => t(item)).join(", ")}`; + }) + .join(". "); + row.push(t("MICROPLAN_ERROR_STATUS_INVALID"), rowDataAddOn); + } else { + row.push(""); + } + } + } + } + processedData[sheet.sheetName] = dataset; + } + const errorColumns = ["MICROPLAN_ERROR_STATUS_COLUMN", "MICROPLAN_ERROR_COLUMN"]; + const style = { + font: { color: { argb: "B91900" } }, + border: { + top: { style: "thin", color: { argb: "B91900" } }, + left: { style: "thin", color: { argb: "B91900" } }, + bottom: { style: "thin", color: { argb: "B91900" } }, + right: { style: "thin", color: { argb: "B91900" } }, + }, + }; + const workbook = await convertToWorkBook(processedData, { errorColumns, style }); + colorHeaders( + workbook, + [...hierarchy.map((item) => t(item)), t(commonColumn)], + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], + [t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN")] + ); + + formatAndColorReadMeFile( + workbook, + readMeData?.map((item) => item?.header), + readMeSheetName + ); + + // protextData + await protectData({ + workbook, + hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, + addFacilityData: schema?.template?.includeFacilityData, + schema, + t, + }); + return await workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { + // Create a Blob from the buffer + return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); + }); + // return xlsxBlob; +}; +export const convertToWorkBook = async (jsonData, columnWithStyle) => { + const workbook = new ExcelJS.Workbook(); + + // Iterate over each sheet in jsonData + for (const [sheetName, data] of Object.entries(jsonData)) { + // Create a new worksheet + const worksheet = workbook.addWorksheet(sheetName); + + // Convert data to worksheet + for (const row of data) { + const newRow = worksheet.addRow(row); + const rowHasData = row?.filter((item) => item !== "").length !== 0; + // Apply red font color to the errorColumn if it exists + if (rowHasData && columnWithStyle?.errorColumns) { + for (const errorColumn of columnWithStyle?.errorColumns) { + const errorColumnIndex = data[0].indexOf(errorColumn); + if (errorColumnIndex !== -1) { + const columnIndex = errorColumnIndex + 1; + if (columnIndex > 0) { + const newCell = newRow.getCell(columnIndex); + if (columnWithStyle.style && newCell) for (const key in columnWithStyle.style) newCell[key] = columnWithStyle.style[key]; + } + } + } + } + } + + // Make the first row bold + if (worksheet.getRow(1)) { + worksheet.getRow(1).font = { bold: true }; + } + + // Set column widths + const columnCount = data?.[0]?.length || 0; + const wscols = Array(columnCount).fill({ width: 30 }); + wscols.forEach((col, colIndex) => { + worksheet.getColumn(colIndex + 1).width = col.width; + }); + } + return workbook; +}; +export const boundaryDataGeneration = async (schemaData, campaignData, t) => { + let boundaryDataAgainstBoundaryCode = {}; + if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { + try { + const rootBoundary = campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable + const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; + let boundaryData = sessionData.filteredBoundaries; + let filteredBoundaries; + if (!boundaryData) { + // Only fetch boundary data if not present in session storage + boundaryData = await fetchBoundaryData(Digit.ULBService.getCurrentTenantId(), campaignData?.hierarchyType, rootBoundary?.[0]?.code); + filteredBoundaries = filterBoundaries(boundaryData, campaignData?.boundaries); + + // Update the session storage with the new filtered boundaries + Digit.SessionStorage.set("microplanHelperData", { + ...sessionData, + filteredBoundaries: filteredBoundaries, + }); + } else { + filteredBoundaries = boundaryData; + } + const xlsxData = addBoundaryData([], filteredBoundaries, campaignData?.hierarchyType)?.[0]?.data; + xlsxData.forEach((item, i) => { + if (i === 0) return; + let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn); + if (boundaryCodeIndex >= item.length) { + // If boundaryCodeIndex is out of bounds, return the item as is + boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(t); + } else { + // Otherwise, remove the element at boundaryCodeIndex + boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item + .slice(0, boundaryCodeIndex) + .concat(item.slice(boundaryCodeIndex + 1)) + .map(t); + } + }); + return boundaryDataAgainstBoundaryCode; + } catch (error) { + console.error(error?.message); + } + } +}; + +export const handleExcelFile = async ( + file, + schemaData, + hierarchy, + selectedFileType, + boundaryDataAgainstBoundaryCode, + setUploadedFileError, + t, + campaignData, + readMeSheetName +) => { + try { + // Converting the file to preserve the sequence of columns so that it can be stored + let fileDataToStore = await parseXlsxToJsonMultipleSheets(file, { header: 0 }); + const additionalSheets = []; + if (fileDataToStore[t(BOUNDARY_DATA_SHEET)]) { + additionalSheets.push({ sheetName: t(BOUNDARY_DATA_SHEET), data: fileDataToStore[t(BOUNDARY_DATA_SHEET)], position: -1 }); + delete fileDataToStore[t(BOUNDARY_DATA_SHEET)]; + } + if (fileDataToStore[t(readMeSheetName)]) { + additionalSheets.push({ sheetName: t(readMeSheetName), data: fileDataToStore[t(readMeSheetName)], position: 0 }); + delete fileDataToStore[t(readMeSheetName)]; + } + let { tempResourceMappingData, tempFileDataToStore } = resourceMappingAndDataFilteringForExcelFiles( + schemaData, + hierarchy, + selectedFileType, + fileDataToStore, + t + ); + fileDataToStore = await convertJsonToXlsx(tempFileDataToStore); + // Converting the input file to json format + let result = await parseXlsxToJsonMultipleSheets(fileDataToStore, { header: 1 }); + if (result?.error) { + return { + check: false, + interruptUpload: true, + error: result.error, + fileDataToStore: {}, + toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") }, + }; + } + let extraColumns = [commonColumn]; + // checking if the hierarchy and common column is present the uploaded data + extraColumns = [...hierarchy, commonColumn]; + let data = Object.values(tempFileDataToStore); + let errorMsg; + let errors; // object containing the location and type of error + let toast; + let hierarchyDataPresent = true; + let latLngColumns = + Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isLocationDataColumns) { + acc.push(key); + } + return acc; + }, []) || []; + data.forEach((item) => { + const keys = item[0]; + if (keys?.length !== 0) { + if (!extraColumns?.every((e) => keys.includes(e))) { + if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { + hierarchyDataPresent = false; + } else { + errorMsg = { + check: false, + interruptUpload: true, + error: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT"), + fileDataToStore: {}, + toast: { state: "error", message: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT") }, + }; + } + } + if (!latLngColumns?.every((e) => keys.includes(e))) { + toast = { state: "warning", message: t("ERROR_UPLOAD_EXCEL_LOCATION_DATA_MISSING") }; + } + } + }); + if (errorMsg && !errorMsg?.check) return errorMsg; + // Running Validations for uploaded file + let response = await checkForErrorInUploadedFileExcel(result, schemaData.schema, t); + if (!response.valid) setUploadedFileError(response.message); + errorMsg = response.message; + errors = response.errors; + const missingProperties = response.missingProperties; + let check = response.valid; + try { + if ( + schemaData && + !schemaData.doHierarchyCheckInUploadedData && + !hierarchyDataPresent && + boundaryDataAgainstBoundaryCode && + (!missingProperties || [...missingProperties]?.includes(commonColumn)) + ) { + let tempBoundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; + for (const sheet in tempFileDataToStore) { + const commonColumnIndex = tempFileDataToStore[sheet]?.[0]?.indexOf(commonColumn); + if (commonColumnIndex !== -1) { + const dataCollector = []; + for (let index = 0; index < tempFileDataToStore[sheet].length; index++) { + let row = tempFileDataToStore[sheet][index]; + const commonColumnValues = row[commonColumnIndex]?.split(",").map((item) => item.trim()); + if (!commonColumnValues) { + dataCollector.push([...new Array(hierarchy.length).fill(""), ...row]); + continue; + } + for (const value of commonColumnValues) { + const newRowData = [...row]; + newRowData[commonColumnIndex] = value; + dataCollector.push([ + ...(tempBoundaryDataAgainstBoundaryCode[value] + ? tempBoundaryDataAgainstBoundaryCode[value] + : index !== 0 + ? new Array(hierarchy.length).fill("") + : []), + ...newRowData, + ]); + } + } + tempFileDataToStore[sheet] = dataCollector; + } + + tempFileDataToStore[sheet][0] = [...hierarchy, ...tempFileDataToStore[sheet][0]]; + } + } + } catch (error) { + console.error("Error in boundary adding operaiton: ", error); + } + tempFileDataToStore = addMissingPropertiesToFileData(tempFileDataToStore, missingProperties); + return { check, errors, errorMsg, fileDataToStore: tempFileDataToStore, tempResourceMappingData, toast, additionalSheets }; + } catch (error) { + console.error("Error in handling Excel file:", error.message); + } +}; +export const addMissingPropertiesToFileData = (data, missingProperties) => { + if (!data || !missingProperties) return data; + let tempData = {}; + Object.entries(data).forEach(([key, value], index) => { + const filteredMissingProperties = [...missingProperties]?.reduce((acc, item) => { + if (!value?.[0]?.includes(item)) { + acc.push(item); + } + return acc; + }, []); + const newTempHeaders = value?.[0].length !== 0 ? [...value[0], ...filteredMissingProperties] : [...filteredMissingProperties]; + tempData[key] = [newTempHeaders, ...value.slice(1)]; + }); + return tempData; +}; + +export const handleGeojsonFile = async (file, schemaData, setUploadedFileError, t) => { + // Reading and checking geojson data + const data = await readGeojson(file, t); + if (!data.valid) { + return { check: false, stopUpload: true, toast: data.toast }; + } + + // Running geojson validaiton on uploaded file + let response = geojsonValidations(data.geojsonData, schemaData.schema, t); + if (!response.valid) setUploadedFileError(response.message); + let check = response.valid; + let error = response.message; + let fileDataToStore = data.geojsonData; + return { check, error, fileDataToStore }; +}; + +const generateLocalisationKeyForSchemaProperties = (code) => { + if (!code) return code; + return `${SCHEMA_PROPERTIES_PREFIX}_${code}`; +}; +export const handleShapefiles = async (file, schemaData, setUploadedFileError, selectedFileType, setToast, t) => { + // Reading and validating the uploaded geojson file + let response = await readAndValidateShapeFiles(file, t, selectedFileType["namingConvention"]); + if (!response.valid) { + setUploadedFileError(response.message); + setToast(response.toast); + } + let check = response.valid; + let error = response.message; + let fileDataToStore = response.data; + return { check, error, fileDataToStore }; +}; + +export const convertToSheetArray = (data) => { + if (!data) return []; + const convertedSheetData = []; + for (const [key, value] of Object.entries(data)) { + convertedSheetData.push({ sheetName: key, data: value }); + } + return convertedSheetData; +}; + +//find guideline +export const findGuideLine = (campaignType, type, section, guidelineArray) => { + if (!guidelineArray) return guidelineArray; + return guidelineArray.find( + (guideline) => + guideline.fileType === type && guideline.templateIdentifier === section && (!guideline.campaignType || guideline.campaignType === campaignType) + )?.guidelines; +}; + +// Utility function to introduce a delay +export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js new file mode 100644 index 00000000000..a2c50215207 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js @@ -0,0 +1,133 @@ +import React, { useState, useEffect } from "react"; +import _ from "lodash"; +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import { configAttendanceApproveModal, configAttendanceRejectModal, configAttendanceCheckModal } from "../config"; + + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const AttendanceActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails, saveAttendanceState}) => { + const [config, setConfig] = useState({}); + + const userUuid = Digit.UserService.getUser()?.info.uuid; + const { isLoading, data:employeeData } = Digit.Hooks.hrms.useHRMSSearch( + { uuids : userUuid }, tenantId + ); + + const empData = employeeData?.Employees[0] + const empDepartment = empData?.assignments?.[0].department + const empDesignation = empData?.assignments?.[0].designation + const empName = empData?.user?.name + + useEffect(() => { + const selectedAction = action?.action + switch(selectedAction) { + case "VERIFY": + submitBasedOnAction(action, 'Verify muster roll') + break; + case "REJECT": + setConfig( + configAttendanceRejectModal({ + t, + action, + empDepartment, + empDesignation, + empName + }) + ) + break; + case "APPROVE": + setConfig( + configAttendanceApproveModal({ + t, + action + }) + ) + break; + case "RESUBMIT": + submitBasedOnAction(action, 'Resubmit muster roll') + break; + case "SAVE": + submitBasedOnAction(action, 'Verify muster roll') + break; + default: + break + } + }, [employeeData]); + + function onSubmit (data) { + submitBasedOnAction(action, data?.comments) + } + + const submitBasedOnAction = (action, comments) => { + let musterRoll = { tenantId, id: applicationDetails?.applicationDetails?.[0]?.applicationData?.id} + let workflow = { action: action?.action, comments: (comments || `${action?.action} done`), assignees: [] } + + const selectedAction = action?.action + switch(selectedAction) { + case "SAVE": + musterRoll.individualEntries = saveAttendanceState?.updatePayload + workflow.action = 'VERIFY' + break; + case "RESUBMIT": + musterRoll.additionalDetails = { computeAttendance : true } + break; + default: + break; + } + const dataTobeSubmitted = {musterRoll, workflow} + submitAction(dataTobeSubmitted) + } + + const cardStyle = () => { + if(config.label.heading === "Processing Details") { + return { + "padding" : "0px" + } + } + return {} + } + + return action && config?.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => {}} + formId="modal-action" + > + + + ) : ( + + ); +} + +export default AttendanceActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js new file mode 100644 index 00000000000..269bbefa1dd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js @@ -0,0 +1,283 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { useQueryClient } from "react-query"; +import { configBPAApproverApplication } from "../config"; +import * as predefinedConfig from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationDetails, applicationData, businessService, moduleCode,workflowDetails }) => { + const mutation1 = Digit.Hooks.obps.useObpsAPI( + applicationData?.landInfo?.address?.city ? applicationData?.landInfo?.address?.city : tenantId, + false + ); + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: workflowDetails?.data?.initialActionState?.nextActions?.filter(ele=>ele?.action==action?.action)?.[0]?.assigneeRoles?.map(role=>({code:role})), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + + const queryClient = useQueryClient(); + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); + const mobileView = Digit.Utils.browser.isMobile() ? true : false; + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { + setError(t(`NOT_SUPPORTED_FILE_TYPE`)) + } else { + try { + const response = await Digit.UploadServices.Filestorage("OBPS", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + const getInspectionDocs = (docs) => { + let refinedDocs = []; + docs && docs.map((doc,ind) => { + refinedDocs.push({ + "documentType":(doc.documentType+"_"+doc.documentType.split("_")[1]).replaceAll("_","."), + "fileStoreId":doc.fileStoreId, + "fileStore":doc.fileStoreId, + "fileName":"", + "dropDownValues": { + "value": (doc.documentType+"_"+doc.documentType.split("_")[1]).replaceAll("_","."), + } + }) + }) + return refinedDocs; + } + + const getQuestion = (data) => { + let refinedQues = []; + var i; + for(i=0; i { + let formdata = [], inspectionOb = []; + + if (data?.additionalDetails?.fieldinspection_pending?.length > 0) { + inspectionOb = data?.additionalDetails?.fieldinspection_pending + } + + if(data.status == "FIELDINSPECTION_INPROGRESS") { + formdata = JSON.parse(sessionStorage.getItem("INSPECTION_DATA")); + formdata?.length > 0 && formdata.map((ob,ind) => { + inspectionOb.push({ + docs: getInspectionDocs(ob.Documents), + date: ob.InspectionDate, + questions: getQuestion(ob), + time: ob?.InspectionTime, + }) + }) + inspectionOb = inspectionOb.filter((ob) => ob.docs && ob.docs.length>0); + } else { + sessionStorage.removeItem("INSPECTION_DATA") + } + + let fieldinspection_pending = [ ...inspectionOb]; + return fieldinspection_pending; + } + + const getDocuments = (applicationData) => { + let documentsformdata = JSON.parse(sessionStorage.getItem("BPA_DOCUMENTS")); + let documentList = []; + documentsformdata.map(doc => { + if(doc?.uploadedDocuments?.[0]?.values?.length > 0) documentList = [...documentList, ...doc?.uploadedDocuments?.[0]?.values]; + if(doc?.newUploadedDocs?.length > 0) documentList = [...documentList, ...doc?.newUploadedDocs] + }); + return documentList; + } + + const getPendingApprovals = () => { + const approvals = Digit.SessionStorage.get("OBPS_APPROVAL_CHECKS"); + const newApprovals = Digit.SessionStorage.get("OBPS_NEW_APPROVALS"); + let result = approvals?.reduce((acc, approval) => approval?.checked ? acc.push(approval?.label) && acc : acc, []); + result = result?.concat(newApprovals !== null?newApprovals.filter(ob => ob.label !== "").map(approval => approval?.label):[]); + return result; + } + + function submit(data) { + let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; + applicationData = { + ...applicationData, + documents: getDocuments(applicationData), + additionalDetails: {...applicationData?.additionalDetails, fieldinspection_pending:getfeildInspection(applicationData), pendingapproval: getPendingApprovals() }, + workflow:{ + action: action?.action, + comment: data?.comments?.length > 0 ? data?.comments : null, + comments: data?.comments?.length > 0 ? data?.comments : null, + assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + assignes: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + varificationDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + }, + action: action?.action, + comment: data?.comments, + assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + wfDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + }; + + const nocDetails = applicationDetails?.nocData?.map(noc => { + const uploadedDocuments = Digit.SessionStorage.get(noc?.nocType) || []; + return { + Noc: { + ...noc, + documents: [ + ...(noc?.documents?noc?.documents:[]), + ...(uploadedDocuments?uploadedDocuments:[]) + ] + } + } + }) + + let nocData = []; + if (nocDetails) { + nocDetails.map(noc => { + if ( + noc?.Noc?.applicationStatus?.toUpperCase() != "APPROVED" && + noc?.Noc?.applicationStatus?.toUpperCase() != "AUTO_APPROVED" && + noc?.Noc?.applicationStatus?.toUpperCase() != "REJECTED" && + noc?.Noc?.applicationStatus?.toUpperCase() != "AUTO_REJECTED" && + noc?.Noc?.applicationStatus?.toUpperCase() != "VOIDED" + ) { + nocData.push(noc); + } + }) + } + + submitAction({ + BPA:applicationData + }, nocData?.length > 0 ? nocData : false, {isStakeholder: false, bpa: true}); + } + + + useEffect(() => { + if (action) { + setConfig( + configBPAApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + assigneeLabel: "WF_ASSIGNEE_NAME_LABEL", + error + }) + ); + } + }, [action, approvers, selectedFinancialYear, uploadedFile, error]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => { }} + formId="modal-action" + isOBPSFlow={true} + popupStyles={mobileView?{width:"720px"}:{}} + style={!mobileView?{minHeight: "45px", height: "auto", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{minHeight: "45px", height: "auto",width:"44%"}} + popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} + > + {PTALoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js new file mode 100644 index 00000000000..dc0bfe07776 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js @@ -0,0 +1,153 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { configBPAREGApproverApplication } from "../config"; +import * as predefinedConfig from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + const mobileView = Digit.Utils.browser.isMobile() ? true : false; + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { + setError(t(`NOT_SUPPORTED_FILE_TYPE`)) + } else { + try { + const response = await Digit.UploadServices.Filestorage("OBPS", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + function submit(data) { + let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; + applicationData = { + ...applicationData, + action: action?.action, + comment: data?.comments, + assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + wfDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + }; + submitAction({ + Licenses: [applicationData], + }, false, {isStakeholder: true, bpa: false}); + } + + useEffect(() => { + if (action) { + setConfig( + configBPAREGApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + error + }) + ); + } + }, [action, approvers, uploadedFile, error]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => { }} + formId="modal-action" + isOBPSFlow={true} + popupStyles={mobileView?{width:"720px"}:{}} + style={!mobileView?{height: "45px", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{height:"45px",width:"44%"}} + popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} + > + {PTALoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js new file mode 100644 index 00000000000..95393b5ae05 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js @@ -0,0 +1,190 @@ +import { Loader, Modal, FormComposer, WorkflowModal } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect, Fragment } from "react"; +import { configViewBillApproveModal, configViewBillRejectModal, configViewBillCheckModal } from "../config"; +import _ from "lodash"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ExpenditureActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails }) => { + + let { loiNumber, estimateNumber } = Digit.Hooks.useQueryParams(); + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + + const [department, setDepartment] = useState([]); + const [selectedDept,setSelectedDept] = useState({}) + + const [designation, setDesignation] = useState([]); + const [selectedDesignation,setSelectedDesignation] = useState({}) + + const mdmsConfig = { + moduleName: "common-masters", + department : { + masterName: "Department", + localePrefix: "COMMON_MASTERS_DEPARTMENT", + }, + designation : { + masterName: "Designation", + localePrefix: "COMMON_MASTERS_DESIGNATION", + } + } + + const { isLoading: mdmsLoading, data: mdmsData,isSuccess:mdmsSuccess } = Digit.Hooks.useCustomMDMS( + Digit.ULBService.getStateId(), + mdmsConfig?.moduleName, + [{name : mdmsConfig?.designation?.masterName}, {name : mdmsConfig?.department?.masterName}, {name : mdmsConfig?.rejectReasons?.masterName}], + { + select: (data) => { + let designationData = _.get(data, `${mdmsConfig?.moduleName}.${mdmsConfig?.designation?.masterName}`, []); + designationData = designationData.filter((opt) => opt?.active).map((opt) => ({ ...opt, name: `${mdmsConfig?.designation?.localePrefix}_${opt.code}` })); + designationData?.map(designation => {designation.i18nKey = designation?.name}) + + let departmentData = _.get(data, `${mdmsConfig?.moduleName}.${mdmsConfig?.department?.masterName}`, []); + departmentData = departmentData.filter((opt) => opt?.active).map((opt) => ({ ...opt, name: `${mdmsConfig?.department?.localePrefix}_${opt.code}` })); + departmentData?.map(department => { department.i18nKey = department?.name}) + + return {designationData, departmentData}; + }, + enabled: mdmsConfig?.moduleName ? true : false, + } + ); + useEffect(() => { + setDepartment(mdmsData?.departmentData) + setDesignation(mdmsData?.designationData) + }, [mdmsData]); + + + + const { isLoading: approverLoading, isError, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ designations: selectedDesignation?.code, departments: selectedDept?.code, roles: action?.assigneeRoles?.toString(), isActive: true }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: action?.action === "CHECK" || action?.action === "TECHNICALSANCATION"}); + + + employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp?.user?.name || "NA") + + useEffect(() => { + setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees.filter(emp => emp?.nameOfEmp !== "NA") : []) + }, [employeeDatav1]) + + useEffect(() => { + + if(action?.action?.includes("CHECK")){ + setConfig( + configViewBillCheckModal({ + t, + action, + businessService, + approvers, + selectedApprover, + setSelectedApprover, + designation, + selectedDesignation, + setSelectedDesignation, + department, + selectedDept, + setSelectedDept, + approverLoading + }) + ) + }else if(action?.action?.includes("APPROVE")){ + setConfig( + configViewBillApproveModal({ + t, + action + }) + ) + } + else if(action?.action?.includes("REJECT")){ + setConfig( + configViewBillRejectModal({ + t, + action, + }) + ) + } + }, [approvers,designation,department]); + + const dummy_exp_response = { + CHECK : { + header: "Bill Forwarded Successfully", + id: "Bill/2021-22/09/0001", + info: "Bill ID", + message: "Bill has been successfully created and forwarded for approval.", + responseData:{}, + requestData:{}, + links : [] + }, + REJECT : { + header: "Bill Rejected Successfully", + id: "Bill/2021-22/09/0001", + info: "Bill ID", + message: "Bill has been Rejected.", + responseData:{}, + requestData:{}, + links : [] + }, + APPROVE : { + header: "Bill Approved Successfully", + id: "Bill/2021-22/09/0001", + info: "Bill ID", + message: "Bill has been approved", + responseData:{}, + requestData:{}, + links : [] + } + } + + + function submit (_data) { + const workflow = { + action: action?.action, + comment: _data?.comments, + response : dummy_exp_response, + type : "bills", + assignees: selectedApprover?.uuid ? [selectedApprover?.uuid] : undefined + } + submitAction({workflow}); + } + + const cardStyle = () => { + if(config.label.heading === "Processing Details") { + return { + "padding" : "0px" + } + } + return {} + } + + return ( + <> + { + action && config?.form ? + + : + mdmsLoading ? + : null + } + ) +} + +export default ExpenditureActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js new file mode 100644 index 00000000000..af0e0e8e701 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js @@ -0,0 +1,298 @@ +import { Loader, Modal, FormComposer, Toast } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { useQueryClient } from "react-query"; + +import { configAssignDso, configCompleteApplication, configReassignDSO, configAcceptDso, configRejectApplication } from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData }) => { + const { data: dsoData, isLoading: isDsoLoading, isSuccess: isDsoSuccess, error: dsoError } = Digit.Hooks.fsm.useDsoSearch(tenantId); + const { isLoading, isSuccess, isError, data: applicationData, error } = Digit.Hooks.fsm.useSearch( + tenantId, + { applicationNos: id }, + { + staleTime: Infinity, + select: (details) => { + let { additionalDetails } = details; + + const parseTillObject = (str) => { + if (typeof str === "object") return str; + else return parseTillObject(JSON.parse(str)); + }; + + additionalDetails = parseTillObject(additionalDetails); + return { ...details, additionalDetails }; + }, + } + ); + const client = useQueryClient(); + const stateCode = Digit.ULBService.getStateId(); + const { data: vehicleList, isLoading: isVehicleData, isSuccess: isVehicleDataLoaded } = Digit.Hooks.fsm.useMDMS( + stateCode, + "Vehicle", + "VehicleType", + { staleTime: Infinity } + ); + const [dsoList, setDsoList] = useState([]); + const [vehicleNoList, setVehicleNoList] = useState([]); + const [config, setConfig] = useState({}); + const [dso, setDSO] = useState(null); + const [vehicleNo, setVehicleNo] = useState(null); + const [vehicleMenu, setVehicleMenu] = useState([]); + const [vehicle, setVehicle] = useState(null); + const [defaultValues, setDefautValue] = useState({ + capacity: vehicle?.capacity, + wasteCollected: vehicle?.capacity, + }); + // const [toastError, setToastError] = useState(false); + const { data: Reason, isLoading: isReasonLoading } = Digit.Hooks.fsm.useMDMS(stateCode, "FSM", "Reason", { staleTime: Infinity }, [ + "ReassignReason", + "RejectionReason", + "DeclineReason", + "CancelReason", + ]); + + const [reassignReason, selectReassignReason] = useState(null); + const [rejectionReason, setRejectionReason] = useState(null); + const [declineReason, setDeclineReason] = useState(null); + const [cancelReason, selectCancelReason] = useState(null); + + const [formValve, setFormValve] = useState(false); + + useEffect(() => { + if (isSuccess && isVehicleDataLoaded) { + const [vehicle] = vehicleList.filter((item) => item.code === applicationData.vehicleType); + setVehicleMenu([vehicle]); + setVehicle(vehicle); + setDefautValue({ + capacity: vehicle?.capacity, + wasteCollected: vehicle?.capacity, + }); + } + }, [isVehicleDataLoaded, isSuccess]); + + useEffect(() => { + if (vehicle && isDsoSuccess) { + const dsoList = dsoData.filter((dso) => dso.vehicles.find((dsoVehicle) => dsoVehicle.type === vehicle.code)); + setDsoList(dsoList); + } + }, [vehicle, isDsoSuccess]); + + useEffect(() => { + if (isSuccess && isDsoSuccess && applicationData.dsoId) { + const [dso] = dsoData.filter((dso) => dso.id === applicationData.dsoId); + const vehicleNoList = dso.vehicles.filter((vehicle) => vehicle.type === applicationData.vehicleType); + setVehicleNoList(vehicleNoList); + } + }, [isSuccess, isDsoSuccess]); + + useEffect(() => { + reassignReason || (actionData && actionData[0] && actionData[0].comment?.length > 0) ? setFormValve(true) : setFormValve(false); + }, [reassignReason]); + + useEffect(() => { + setFormValve(rejectionReason ? true : false); + }, [rejectionReason]); + + useEffect(() => { + setFormValve(declineReason ? true : false); + }, [declineReason]); + + useEffect(() => { + setFormValve(cancelReason ? true : false); + }, [cancelReason]); + + function selectDSO(dsoDetails) { + setDSO(dsoDetails); + } + + function selectVehicleNo(vehicleNo) { + setVehicleNo(vehicleNo); + } + + function selectVehicle(value) { + setVehicle(value); + setDefautValue({ + capacity: value?.capacity, + wasteCollected: value?.capacity, + }); + } + + function addCommentToWorkflow(state, workflow, data) { + workflow.comments = data.comments ? state.code + "~" + data.comments : state.code; + } + + function submit(data) { + const workflow = { action: action }; + + if (dso) applicationData.dsoId = dso.id; + if (vehicleNo && action === "ACCEPT") applicationData.vehicleId = vehicleNo.id; + if (vehicleNo && action === "DSO_ACCEPT") applicationData.vehicleId = vehicleNo.id; + if (vehicle && action === "ASSIGN") applicationData.vehicleType = vehicle.code; + if (data.date) applicationData.possibleServiceDate = new Date(`${data.date}`).getTime(); + if (data.desluged) applicationData.completedOn = new Date(data.desluged).getTime(); + if (data.wasteCollected) applicationData.wasteCollected = data.wasteCollected; + if (reassignReason) addCommentToWorkflow(reassignReason, workflow, data); + if (rejectionReason) addCommentToWorkflow(rejectionReason, workflow, data); + if (declineReason) addCommentToWorkflow(declineReason, workflow, data); + if (cancelReason) addCommentToWorkflow(cancelReason, workflow, data); + + submitAction({ fsm: applicationData, workflow }); + } + useEffect(() => { + switch (action) { + case "DSO_ACCEPT": + case "ACCEPT": + setFormValve(vehicleNo ? true : false); + return setConfig( + configAcceptDso({ + t, + dsoData, + dso, + vehicle, + vehicleNo, + vehicleNoList, + selectVehicleNo, + action, + }) + ); + + case "ASSIGN": + case "GENERATE_DEMAND": + case "FSM_GENERATE_DEMAND": + setFormValve(dso && vehicle ? true : false); + return setConfig( + configAssignDso({ + t, + dsoData, + dso, + selectDSO, + vehicleMenu, + vehicle, + selectVehicle, + action, + }) + ); + case "REASSIGN": + case "REASSING": + case "FSM_REASSING": + dso && vehicle && (reassignReason || (actionData && actionData[0] && actionData[0].comment?.length > 0)) + ? setFormValve(true) + : setFormValve(false); + return setConfig( + configReassignDSO({ + t, + dsoData, + dso, + selectDSO, + vehicleMenu, + vehicle, + selectVehicle, + reassignReasonMenu: Reason?.ReassignReason, + reassignReason, + selectReassignReason, + action, + showReassignReason: actionData && actionData[0] && actionData[0].comment?.length > 0 ? false : true, + }) + ); + case "COMPLETE": + case "COMPLETED": + setFormValve(true); + return setConfig(configCompleteApplication({ t, vehicle, applicationCreatedTime: applicationData?.auditDetails?.createdTime, action })); + case "SUBMIT": + case "FSM_SUBMIT": + return history.push(`/${window?.contextPath}/employee/fsm/modify-application/` + applicationNumber); + case "DECLINE": + case "DSO_REJECT": + //declinereason + setFormValve(declineReason ? true : false); + return setConfig( + configRejectApplication({ + t, + rejectMenu: Reason?.DeclineReason, + setReason: setDeclineReason, + reason: declineReason, + action, + }) + ); + case "REJECT": + case "SENDBACK": + // rejectionReason + setFormValve(rejectionReason ? true : false); + return setConfig( + configRejectApplication({ + t, + rejectMenu: Reason?.RejectionReason, + setReason: setRejectionReason, + reason: rejectionReason, + action, + }) + ); + case "CANCEL": + ///cancellreason + setFormValve(cancelReason ? true : false); + return setConfig( + configRejectApplication({ + t, + rejectMenu: Reason?.CancelReason, + setReason: selectCancelReason, + reason: cancelReason, + action, + }) + ); + + case "PAY": + case "ADDITIONAL_PAY_REQUEST": + case "FSM_PAY": + return history.push(`/${window?.contextPath}/employee/payment/collect/FSM.TRIP_CHARGES/${applicationNumber}`); + default: + break; + } + }, [action, isDsoLoading, dso, vehicleMenu, rejectionReason, vehicleNo, vehicleNoList, Reason]); + + return action && config.form && !isDsoLoading && !isReasonLoading && isVehicleDataLoaded ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => {}} + formId="modal-action" + isDisabled={!formValve} + > + + {/* {toastError && } */} + + ) : ( + + ); +}; + +export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js new file mode 100644 index 00000000000..09266ca1b7b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js @@ -0,0 +1,169 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { useQueryClient } from "react-query"; +import { useHistory } from "react-router-dom"; +import { configNOCApproverApplication } from "../config"; +import * as predefinedConfig from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { + + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + + const queryClient = useQueryClient(); + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + const mobileView = Digit.Utils.browser.isMobile() ? true : false; + const history = useHistory(); + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { + setError(t(`NOT_SUPPORTED_FILE_TYPE`)) + } else { + try { + const response = await Digit.UploadServices.Filestorage("NOC", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + + function submit(data) { + let enteredDocs = JSON.parse(sessionStorage.getItem("NewNOCDocs")); + let newDocs = applicationData?.documents?.length > 0 ? [...applicationData?.documents] : []; + enteredDocs.map((d,index) => { + newDocs.push(d); + }) + applicationData = { + ...applicationData, + workflow:{ + action: action?.action, + comment: data?.comments ? data?.comments : null, + assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + documents: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + }, + documents: newDocs, + }; + + + submitAction({ + Noc: applicationData, + }, false, {isNoc: true}); + } + + useEffect(() => { + if (action) { + setConfig( + configNOCApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + assigneeLabel: "WF_ASSIGNEE_NAME_LABEL", + error + }) + ); + } + }, [action, approvers, uploadedFile, error]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => { }} + formId="modal-action" + isOBPSFlow={true} + popupStyles={mobileView?{width:"720px"}:{}} + style={!mobileView?{height: "45px", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{height:"45px",width:"44%"}} + popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} + > + {PTALoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js new file mode 100644 index 00000000000..37b3d996177 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js @@ -0,0 +1,190 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; + +import { configPTApproverApplication, configPTAssessProperty } from "../config"; +import * as predefinedConfig from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + const { isLoading: financialYearsLoading, data: financialYearsData } = Digit.Hooks.pt.useMDMS( + tenantId, + businessService, + "FINANCIAL_YEARLS", + {}, + { + details: { + tenantId: Digit.ULBService.getStateId(), + moduleDetails: [{ moduleName: "egf-master", masterDetails: [{ name: "FinancialYear", filter: "[?(@.module == 'PT')]" }] }], + }, + } + ); + + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState(null); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + const [financialYears, setFinancialYears] = useState([]); + const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); + const [disableActionSubmit, setDisableActionSubmit] = useState(false); + + useEffect(() => { + if (financialYearsData && financialYearsData["egf-master"]) { + setFinancialYears(financialYearsData["egf-master"]?.["FinancialYear"]); + } + }, [financialYearsData]); + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else { + try { + const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + function submit(data) { + if (!action?.showFinancialYearsModal) { + let workflow = { action: action?.action, comment: data?.comments, businessService, moduleName: moduleCode }; + workflow["assignes"] = action?.isTerminateState || !selectedApprover ? [] : [selectedApprover]; + if (uploadedFile) + workflow["documents"] = [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ]; + + submitAction({ + Property: { + ...applicationData, + workflow, + }, + }); + } else { + submitAction({ + customFunctionToExecute: action?.customFunctionToExecute, + Assessment: { + financialYear: selectedFinancialYear?.name, + propertyId: applicationData?.propertyId, + tenantId, + source: applicationData?.source, + channel: applicationData?.channel, + assessmentDate: Date.now(), + }, + }); + } + } + + useEffect(() => { + if (action) { + if (action?.showFinancialYearsModal) { + setConfig( + configPTAssessProperty({ + t, + action, + financialYears, + selectedFinancialYear, + setSelectedFinancialYear, + }) + ); + } else { + setConfig( + configPTApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + }) + ); + } + } + }, [action, approvers, financialYears, selectedFinancialYear, uploadedFile]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => {}} + isDisabled={!action.showFinancialYearsModal ? PTALoading || (action?.docUploadRequired && !uploadedFile) : !selectedFinancialYear} + formId="modal-action" + > + {financialYearsLoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js new file mode 100644 index 00000000000..f11658a987a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js @@ -0,0 +1,166 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; + +import { configTLApproverApplication } from "../config"; +import * as predefinedConfig from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + const { isLoading: financialYearsLoading, data: financialYearsData } = Digit.Hooks.pt.useMDMS( + tenantId, + businessService, + "FINANCIAL_YEARLS", + {}, + { + details: { + tenantId: Digit.ULBService.getStateId(), + moduleDetails: [{ moduleName: "egf-master", masterDetails: [{ name: "FinancialYear", filter: "[?(@.module == 'TL')]" }] }], + }, + } + ); + + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + const [financialYears, setFinancialYears] = useState([]); + const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); + + useEffect(() => { + if (financialYearsData && financialYearsData["egf-master"]) { + setFinancialYears(financialYearsData["egf-master"]?.["FinancialYear"]); + } + }, [financialYearsData]); + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else { + try { + const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + function submit(data) { + let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; + applicationData = { + ...applicationData, + action: action?.action, + comment: data?.comments, + assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + // assignee: action?.isTerminateState ? [] : [selectedApprover?.uuid], + wfDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + }; + submitAction({ + Licenses: [applicationData], + }); + } + + useEffect(() => { + if (action) { + setConfig( + configTLApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + }) + ); + } + }, [action, approvers, financialYears, selectedFinancialYear, uploadedFile]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => {}} + // isDisabled={!action.showFinancialYearsModal ? PTALoading || (!action?.isTerminateState && !selectedApprover?.uuid) : !selectedFinancialYear} + formId="modal-action" + > + {financialYearsLoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js new file mode 100644 index 00000000000..eb64a09804b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js @@ -0,0 +1,261 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { configWSApproverApplication, configWSDisConnectApplication } from "../config"; +import * as predefinedConfig from "../config"; +import cloneDeep from "lodash/cloneDeep"; + + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const convertDateToEpochNew = (dateString, dayStartOrEnd = "dayend") => { + //example input format : "2018-10-02" + try { + const parts = dateString.match(/(\d{4})-(\d{1,2})-(\d{1,2})/); + const DateObj = new Date(Date.UTC(parts[1], parts[3] - 1, parts[2])); + + DateObj.setMinutes(DateObj.getMinutes() + DateObj.getTimezoneOffset()); + if (dayStartOrEnd === "dayend") { + DateObj.setHours(DateObj.getHours() + 24); + DateObj.setSeconds(DateObj.getSeconds() - 1); + } + return DateObj.getTime(); + } catch (e) { + return dateString; + } +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { + setError(t(`NOT_SUPPORTED_FILE_TYPE`)) + } else { + try { + const response = await Digit.UploadServices.Filestorage("WS", file, Digit.ULBService.getCurrentTenantId()); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + console.error("Modal -> err ", err); + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + function submit(data) { + if(applicationData?.isBillAmend){ + const comments = data?.comments ? data.comments : null + + const additionalDetails = { ...applicationData?.billAmendmentDetails?.additionalDetails, comments } + const amendment = { + ...applicationData?.billAmendmentDetails, + workflow:{ + businessId:applicationData?.billAmendmentDetails?.amendmentId, + action:action?.action, + tenantId:tenantId, + businessService:"BS.AMENDMENT", + moduleName:"BS" + }, + additionalDetails, + comment: data?.comments || "", + wfDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + processInstance: { + action: action?.action, + assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], + comment: data?.comments || "", + documents: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : [] + } + } + //amendment?.additionalDetails?.comments = comments + submitAction({AmendmentUpdate:amendment}) + return + } + let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; + applicationData = { + ...applicationData, + action: action?.action, + comment: data?.comments || "", + assignee: !selectedApprover?.uuid ? [] : [selectedApprover?.uuid], + assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], + wfDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + processInstance: { + ...applicationData?.processInstance, + action: action?.action, + assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], + comment: data?.comments || "", + documents: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : [] + } + }; + + if (data?.date) { + const connectionExecutionDate = cloneDeep(data?.date); + applicationData.connectionExecutionDate = convertDateToEpochNew(connectionExecutionDate) + } + if (applicationData?.processInstance?.businessService == "DisconnectWSConnection" || applicationData?.processInstance?.businessService == "DisconnectSWConnection"){ + applicationData?.serviceType == "WATER" ? + submitAction({ WaterConnection: applicationData, disconnectRequest: true }) : + submitAction({ SewerageConnection: applicationData, disconnectRequest: true }) + } else { + const adhocRebateData = sessionStorage.getItem("Digit.ADHOC_ADD_REBATE_DATA"); + const parsedAdhocRebateData = adhocRebateData ? JSON.parse(adhocRebateData) : ""; + if (parsedAdhocRebateData?.value?.adhocPenalty) applicationData.additionalDetails.adhocPenalty = parseInt(parsedAdhocRebateData?.value?.adhocPenalty) || ""; + if (parsedAdhocRebateData?.value?.adhocPenaltyComment) applicationData.additionalDetails.adhocPenaltyComment = parsedAdhocRebateData?.value?.adhocPenaltyComment || ""; + if (parsedAdhocRebateData?.value?.adhocPenaltyReason) applicationData.additionalDetails.adhocPenaltyReason = parsedAdhocRebateData?.value?.adhocPenaltyReason || ""; + if (parsedAdhocRebateData?.value?.adhocRebate) applicationData.additionalDetails.adhocRebate = parseInt(parsedAdhocRebateData?.value?.adhocRebate) || ""; + if (parsedAdhocRebateData?.value?.adhocRebateComment) applicationData.additionalDetails.adhocRebateComment = parsedAdhocRebateData?.value?.adhocRebateComment || ""; + if (parsedAdhocRebateData?.value?.adhocRebateReason) applicationData.additionalDetails.adhocRebateReason = parsedAdhocRebateData?.value?.adhocRebateReason || ""; + applicationData?.serviceType == "WATER" ? submitAction({ WaterConnection: applicationData }) : submitAction({ SewerageConnection: applicationData }); + } + } + + useEffect(() => { + if (applicationData?.processInstance?.businessService == "DisconnectWSConnection" || applicationData?.processInstance?.businessService == "DisconnectSWConnection") { + if (action) { + setConfig( + configWSDisConnectApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + error + }) + ); + } + } else { + if (action) { + setConfig( + configWSApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + error + }) + ); + } + } + }, [action, approvers, uploadedFile, error]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => { }} + formId="modal-action" + > + {PTALoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js new file mode 100644 index 00000000000..dd19cf33a1e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js @@ -0,0 +1,262 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { configApproveModal, configRejectModal, configCheckModal } from "../config"; + +import cloneDeep from "lodash/cloneDeep"; + + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const convertDateToEpochNew = (dateString, dayStartOrEnd = "dayend") => { + //example input format : "2018-10-02" + try { + const parts = dateString.match(/(\d{4})-(\d{1,2})-(\d{1,2})/); + const DateObj = new Date(Date.UTC(parts[1], parts[3] - 1, parts[2])); + + DateObj.setMinutes(DateObj.getMinutes() + DateObj.getTimezoneOffset()); + if (dayStartOrEnd === "dayend") { + DateObj.setHours(DateObj.getHours() + 24); + DateObj.setSeconds(DateObj.getSeconds() - 1); + } + return DateObj.getTime(); + } catch (e) { + return dateString; + } +}; + + +const WorksActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails }) => { + //here according to the action selected render appropriate modal + + // const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + // tenantId, + // { + // roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + // isActive: true, + // }, + // { enabled: !action?.isTerminateState } + // ); + let { loiNumber, estimateNumber } = Digit.Hooks.useQueryParams(); + const [config, setConfig] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + + const [department, setDepartment] = useState([]); + const [selectedDept,setSelectedDept] = useState({}) + + const [rejectionReason, setRejectionReason] = useState([]); + const [selectedReason,setSelectedReason] = useState([]) + + const [designation, setDesignation] = useState([]); + const [selectedDesignation,setSelectedDesignation] = useState({}) + + //get approverDept,designation,approver(hrms),rejectionReason + + const rejectReasons = [ + { + name: "Estimate Details are incorrect" + }, + { + name: "Financial Details are incorrect" + }, + { + name: "Agreement Details are incorrect" + }, + { + name: "Vendor Details are incorrect" + }, + { + name: "Attachments provided are wrong" + }, + { + name: "Others" + }, + ] + + const { isLoading: mdmsLoading, data: mdmsData,isSuccess:mdmsSuccess } = Digit.Hooks.useCustomMDMS( + Digit.ULBService.getCurrentTenantId(), + "common-masters", + [ + { + "name": "Designation" + }, + { + "name": "Department" + } + ] + ); + + mdmsData?.["common-masters"]?.Designation?.map(designation => { + designation.i18nKey = `ES_COMMON_DESIGNATION_${designation?.name}` + }) + + mdmsData?.["common-masters"]?.Department?.map(department => { + department.i18nKey = `ES_COMMON_${department?.code}` + }) + // const { data: approverData, isLoading: approverLoading } = Digit.Hooks.useEmployeeSearch( + // tenantId, + // { + // roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + // isActive: true, + // }, + // { enabled: !action?.isTerminateState } + // ); + + + // const { isLoading: approverLoading, isError,isSuccess:approverSuccess, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ Designation: selectedDesignation?.code, Department: selectedDept?.code }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: !!(selectedDept?.code && selectedDesignation?.code) }); + // employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp.user.name) + + + // useEffect(() => { + + // setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + // }, [approverData]); + + useEffect(() => { + + //setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + //setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees : []) + setDepartment(mdmsData?.["common-masters"]?.Department) + setDesignation(mdmsData?.["common-masters"]?.Designation) + setRejectionReason(rejectReasons) + }, [mdmsData]); + + + + const { isLoading: approverLoading, isError, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ designations: selectedDesignation?.code, departments: selectedDept?.code, roles: action?.assigneeRoles?.toString(), isActive: true }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: action?.action === "CHECK" || action?.action === "TECHNICALSANCATION"}); + + + employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp?.user?.name || "NA") + + useEffect(() => { + setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees.filter(emp => emp?.nameOfEmp !== "NA") : []) + }, [employeeDatav1]) + + + // if (employeeDatav1?.Employees?.length > 0) { + // setApprovers(employeeDatav1?.Employees) + // } + + useEffect(() => { + + if(action?.action?.includes("CHECK") || action?.action?.includes("TECHNICALSANCATION")){ + setConfig( + configCheckModal({ + t, + action, + businessService, + approvers, + selectedApprover, + setSelectedApprover, + designation, + selectedDesignation, + setSelectedDesignation, + department, + selectedDept, + setSelectedDept, + approverLoading + }) + ) + }else if(action?.action?.includes("APPROVE") || action?.action?.includes("ADMINSANCTION")){ + setConfig( + configApproveModal({ + t, + action + }) + ) + } + else if(action?.action?.includes("REJECT")){ + setConfig( + configRejectModal({ + t, + action, + rejectReasons, + selectedReason, + setSelectedReason, + loiNumber, + department, + estimateNumber + }) + ) + } + }, [approvers,designation,department]); + + + function submit (_data) { + //make the update object here and call submitAction + //if the action is reject then you need to make a search call and get creater's uuid + const workflow = { + action: action?.action, + comment: _data?.comments, + assignees: selectedApprover?.uuid ? [selectedApprover?.uuid] : undefined + } + + if(action?.action.includes("REJECT")) { + workflow.assignee = [applicationData?.auditDetails?.createdBy] + } + + Object.keys(workflow).forEach(key => { + if (workflow[key] === undefined) { + delete workflow[key]; + } + }); + {estimateNumber ? submitAction({estimate:applicationData,workflow}) : + submitAction({letterOfIndent:applicationData,workflow})} + + } + + // if(mdmsLoading || approverLoading ) { + // return + // } + + + + + + return action && config?.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => { }} + formId="modal-action" + > + {mdmsLoading ? ( + + ) : ( + + )} + + ) : ( + + ); +} + +export default WorksActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js new file mode 100644 index 00000000000..56465790b8b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js @@ -0,0 +1,49 @@ +import React, { useState, useEffect } from "react"; +import FSMActionModal from "./FSMActionModal"; +import PTActionModal from "./PTActionModal"; +import TLActionModal from "./TLActionModal"; +import BPAREGActionModal from "./BPAREGActionModal"; +import BPAActionModal from "./BPAActionModal"; +import NOCActionModal from "./NOCActionModal"; +import WNSActionModal from "./WNSActionModal"; +import WorksActionModal from "./WorksActionModal"; +import AttendanceActionModal from "./AttendanceActionModal"; +import ExpenditureActionModal from "./ExpenditureActionModal"; + +const ActionModal = (props) => { + if (props?.businessService.includes("PT")) { + return ; + } + + if (props?.businessService.includes("NewTL") || props?.businessService.includes("TL") || props?.businessService.includes("EDITRENEWAL") || props?.businessService.includes("DIRECTRENEWAL")) { + return ; + } + + if (props?.moduleCode.includes("BPAREG")) { + return ; + } + + if (props?.moduleCode.includes("BPA")) { + return ; + } + + if (props?.moduleCode.includes("NOC")) { + return ; + } + + if (props?.moduleCode.includes("WS")) { + return ; + } + if (props?.moduleCode.includes("works")) { + return ; + } + if (props?.moduleCode.includes("AttendenceMgmt")) { + return ; + } + if (props?.moduleCode.includes("Expenditure")) { + return ; + } + +}; + +export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js new file mode 100644 index 00000000000..7ad3a0f95ce --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js @@ -0,0 +1,80 @@ +import React, {useEffect, useRef} from "react"; +import { useTranslation } from "react-i18next"; +import { SubmitBar, ActionBar, Menu } from "@egovernments/digit-ui-react-components"; + +function ApplicationDetailsActionBar({ workflowDetails, displayMenu, onActionSelect, setDisplayMenu, businessService, forcedActionPrefix,ActionBarStyle={},MenuStyle={}, saveAttendanceState }) { + const { t } = useTranslation(); + let user = Digit.UserService.getUser(); + const menuRef = useRef(); + if (window.location.href.includes("/obps") || window.location.href.includes("/noc")) { + const userInfos = sessionStorage.getItem("Digit.citizen.userRequestObject"); + const userInfo = userInfos ? JSON.parse(userInfos) : {}; + user = userInfo?.value; + } + const userRoles = user?.info?.roles?.map((e) => e.code); + let isSingleButton = false; + let isMenuBotton = false; + let actions = workflowDetails?.data?.actionState?.nextActions?.filter((e) => { + return userRoles.some((role) => e.roles?.includes(role)) || !e.roles; + }) || workflowDetails?.data?.nextActions?.filter((e) => { + return userRoles.some((role) => e.roles?.includes(role)) || !e.roles; + }); + + const closeMenu = () => { + setDisplayMenu(false); + } + Digit.Hooks.useClickOutside(menuRef, closeMenu, displayMenu ); + + if (((window.location.href.includes("/obps") || window.location.href.includes("/noc")) && actions?.length == 1) || (actions?.[0]?.redirectionUrl?.pathname.includes("/pt/property-details/")) && actions?.length == 1) { + isMenuBotton = false; + isSingleButton = true; + } else if (actions?.length > 0) { + isMenuBotton = true; + isSingleButton = false; + } + + if(saveAttendanceState?.displaySave) { + isMenuBotton = false; + isSingleButton = true; + actions = [ + { + action: "SAVE", + state: "UPDATED" + } + ] + } + + return ( + + {!workflowDetails?.isLoading && isMenuBotton && !isSingleButton && ( + + {displayMenu && (workflowDetails?.data?.actionState?.nextActions || workflowDetails?.data?.nextActions) ? ( + + ) : null} + setDisplayMenu(!displayMenu)} /> + + )} + {!workflowDetails?.isLoading && !isMenuBotton && isSingleButton && ( + + + + )} + + ); +} + +export default ApplicationDetailsActionBar; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js new file mode 100644 index 00000000000..5596d7b694b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js @@ -0,0 +1,484 @@ +import { + BreakLine, + Card, + CardSectionHeader, + CardSubHeader, + CheckPoint, + CollapseAndExpandGroups, + ConnectingCheckPoints, + ViewImages, + Loader, + Row, + StatusTable, + Table, +} from "@egovernments/digit-ui-react-components"; +import { values } from "lodash"; +import React, { Fragment, useCallback, useReducer, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Link } from "react-router-dom"; +import BPADocuments from "./BPADocuments"; +import InspectionReport from "./InspectionReport"; +import NOCDocuments from "./NOCDocuments"; +import PermissionCheck from "./PermissionCheck"; +import PropertyDocuments from "./PropertyDocuments"; +import PropertyEstimates from "./PropertyEstimates"; +import PropertyFloors from "./PropertyFloors"; +import PropertyOwners from "./PropertyOwners"; +import ScruntinyDetails from "./ScruntinyDetails"; +import SubOccupancyTable from "./SubOccupancyTable"; +import TLCaption from "./TLCaption"; +import TLTradeAccessories from "./TLTradeAccessories"; +import TLTradeUnits from "./TLTradeUnits"; +//import WSAdditonalDetails from "./WSAdditonalDetails"; +import WSFeeEstimation from "./WSFeeEstimation"; +//import WSInfoLabel from "../../../ws/src/pageComponents/WSInfoLabel"; +import DocumentsPreview from "./DocumentsPreview"; +import InfoDetails from "./InfoDetails"; +import ViewBreakup from "./ViewBreakup"; +import SubWorkTableDetails from "./SubWorkTableDetails"; + + + +function ApplicationDetailsContent({ + applicationDetails, + workflowDetails, + isDataLoading, + applicationData, + businessService, + timelineStatusPrefix, + showTimeLine = true, + statusAttribute = "status", + paymentsList, + oldValue, + isInfoLabel = false, + noBoxShadow = false, + sectionHeadStyle = false, + modify, + setSaveAttendanceState +}) { + const { t } = useTranslation(); + const [localSearchParams, setLocalSearchParams] = useState(() => ({})); + + + const handleDateRangeChange = useCallback((data) => { + setLocalSearchParams(() => ({ ...data })); + }, []); + + function OpenImage(imageSource, index, thumbnailsToShow) { + window.open(thumbnailsToShow?.fullImage?.[0], "_blank"); + } + + const convertEpochToDateDMY = (dateEpoch) => { + if (dateEpoch == null || dateEpoch == undefined || dateEpoch == "") { + return "NA"; + } + const dateFromApi = new Date(dateEpoch); + let month = dateFromApi.getMonth() + 1; + let day = dateFromApi.getDate(); + let year = dateFromApi.getFullYear(); + month = (month > 9 ? "" : "0") + month; + day = (day > 9 ? "" : "0") + day; + return `${day}/${month}/${year}`; + }; + const getTimelineCaptions = (checkpoint) => { + if (checkpoint.state === "OPEN" || (checkpoint.status === "INITIATED" && !window.location.href.includes("/obps/"))) { + const caption = { + date: convertEpochToDateDMY(applicationData?.auditDetails?.createdTime), + source: applicationData?.channel || "", + }; + return ; + } else if (window.location.href.includes("/obps/") || window.location.href.includes("/noc/") || window.location.href.includes("/ws/")) { + //From BE side assigneeMobileNumber is masked/unmasked with connectionHoldersMobileNumber and not assigneeMobileNumber + const privacy = { uuid: checkpoint?.assignes?.[0]?.uuid, fieldName: ["connectionHoldersMobileNumber"], model: "WaterConnectionOwner" }; + const caption = { + date: checkpoint?.auditDetails?.lastModified, + name: checkpoint?.assignes?.[0]?.name, + mobileNumber: + applicationData?.processInstance?.assignes?.[0]?.uuid === checkpoint?.assignes?.[0]?.uuid && + applicationData?.processInstance?.assignes?.[0]?.mobileNumber + ? applicationData?.processInstance?.assignes?.[0]?.mobileNumber + : checkpoint?.assignes?.[0]?.mobileNumber, + comment: t(checkpoint?.comment), + wfComment: checkpoint.wfComment, + thumbnailsToShow: checkpoint?.thumbnailsToShow, + }; + return ; + } else { + const caption = { + date: `${Digit.DateUtils?.ConvertTimestampToDate(checkpoint.auditDetails.lastModifiedEpoch)} ${Digit.DateUtils?.ConvertEpochToTimeInHours( + checkpoint.auditDetails.lastModifiedEpoch + )} ${Digit.DateUtils?.getDayfromTimeStamp(checkpoint.auditDetails.lastModifiedEpoch)}`, + // name: checkpoint?.assigner?.name, + name: checkpoint?.assignes?.[0]?.name, + // mobileNumber: checkpoint?.assigner?.mobileNumber, + wfComment: checkpoint?.wfComment, + mobileNumber: checkpoint?.assignes?.[0]?.mobileNumber, + }; + + return ; + } + }; + + const getTranslatedValues = (dataValue, isNotTranslated) => { + if (dataValue) { + return !isNotTranslated ? t(dataValue) : dataValue; + } else { + return t("NA"); + } + }; + + const checkLocation = + window.location.href.includes("employee/tl") || window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc"); + const isNocLocation = window.location.href.includes("employee/noc"); + const isBPALocation = window.location.href.includes("employee/obps"); + let isWS = window.location.href.includes("employee/ws") || window.location.href.includes("employee/works")|| window.location.href.includes("employee/project") || window.location.href.includes("employee/estimate") ; + + + + const getRowStyles = (tab="") => { + + if (window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc")) { + return { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; + } else if (checkLocation) { + return { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; + } + else if ( tab==="fieldSurvey") { + return { + justifyContent: "space-between", flexDirection:"column" + } + } + else { + return {}; + } + + }; + const getTextStyles = (tab="") => { + if ( tab==="fieldSurvey" ) { + return { + marginTop:"1rem", + marginBottom:"1rem" + } + } + else { + return {}; + } + + }; + const getLabelStyles = (tab = "") => { + if ( tab === "fieldSurvey") { + return { + width:"100%" + } + } + else { + return {}; + } + + }; + + const getTableStyles = () => { + if (window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc")) { + return { position: "relative", marginTop: "19px" }; + } else if (checkLocation) { + return { position: "relative", marginTop: "19px" }; + } else { + return {}; + } + }; + + const getMainDivStyles = () => { + if ( + window.location.href.includes("employee/obps") || + window.location.href.includes("employee/noc") || + window.location.href.includes("employee/ws") || + window.location.href.includes("employee/works") || + window.location.href.includes("employee/contracts") + ) { + return { lineHeight: "19px", maxWidth: "950px", minWidth: "280px" }; + } else if (checkLocation) { + return { lineHeight: "19px", maxWidth: "600px", minWidth: "280px" }; + } else { + return {}; + } + }; + + const getTextValue = (value) => { + if (value?.skip) return value.value; + else if (value?.isUnit) return value?.value ? `${getTranslatedValues(value?.value, value?.isNotTranslated)} ${t(value?.isUnit)}` : t("N/A"); + else if (value?.value === "Approved") return { `${getTranslatedValues(value?.value, value?.isNotTranslated)}`} + else if (value?.value === "Rejected") return {t(value?.value)} + else return value?.value ? getTranslatedValues(value?.value, value?.isNotTranslated) : t("N/A"); + }; + + const getClickInfoDetails = () => { + if (window.location.href.includes("disconnection") || window.location.href.includes("application")) { + return "WS_DISCONNECTION_CLICK_ON_INFO_LABEL"; + } else { + return "WS_CLICK_ON_INFO_LABEL"; + } + }; + + const getClickInfoDetails1 = () => { + if (window.location.href.includes("disconnection") || window.location.href.includes("application")) { + return "WS_DISCONNECTION_CLICK_ON_INFO1_LABEL"; + } else { + return ""; + } + }; + + const getCardStyles = () => { + let styles = { position: "relative" } + if (noBoxShadow) styles = { ...styles, boxShadow: "none" }; + return styles; + }; + + return ( + + + {isInfoLabel ? ( + + ) : null} + {applicationDetails?.applicationDetails?.map((detail, index) => ( + + +
+ {index === 0 && !detail.asSectionHeader ? ( + {t(detail.title)} + ) : ( + + + {isNocLocation ? `${t(detail.title)}` : t(detail.title)} + {detail?.Component ? : null} + + + )} + {/* TODO, Later will move to classes */} + {/* Here Render the table for adjustment amount details detail.isTable is true for that table*/} + {/* {detail?.isTable && ( + + + {detail?.headers.map((header) => ( + + ))} + + + {detail?.tableRows.map((row,index)=>{ + if(index===detail?.tableRows.length - 1){ + return <> +
+ + {row.map(element => )} + + + } + return + {row.map(element => )} + })} +
{t(header)}
{t(element)}
{t(element)}
+ )} */} + {detail?.isTable && } + + + {detail?.title && + !detail?.title.includes("NOC") && + detail?.values?.map((value, index) => { + if (value.map === true && value.value !== "N/A") { + return } />; + } + if (value?.isLink == true) { + return ( + + + + {t(value?.title)} + + +
+ ) : isNocLocation || isBPALocation ? ( + `${t(value.title)}` + ) : ( + t(value.title) + ) + } + text={ +
+ + + {value?.value} + + +
+ } + last={index === detail?.values?.length - 1} + caption={value.caption} + className="border-none" + rowContainerStyle={getRowStyles()} + /> + ); + } + return ( + { }} />: getTextValue(value)} + last={index === detail?.values?.length - 1} + caption={value.caption} + className="border-none" + /* privacy object set to the Row Component */ + privacy={value?.privacy} + // TODO, Later will move to classes + rowContainerStyle={getRowStyles(detail?.tab)} + textStyle={getTextStyles(detail?.tab)} + labelStyle={getLabelStyles(detail?.tab)} + /> + ); + })} + +
+ + + {detail?.additionalDetails?.table + ? detail?.additionalDetails?.table?.weekTable?.tableHeader && ( + <> + + {t(detail?.additionalDetails?.table?.weekTable?.tableHeader)} + + + ) + : null} + + {detail?.additionalDetails?.inspectionReport && ( + + )} + {applicationDetails?.applicationData?.additionalDetails?.fieldinspection_pending?.length > 0 && detail?.additionalDetails?.fiReport && ( + + )} + {/* {detail?.additionalDetails?.FIdocuments && detail?.additionalDetails?.values?.map((doc,index) => ( +
+ {doc.isNotDuplicate &&
+ + + +
+
+
} +
+ )) } */} + {detail?.additionalDetails?.floors && } + {detail?.additionalDetails?.owners && } + {detail?.additionalDetails?.units && } + {detail?.additionalDetails?.accessories && } + {detail?.additionalDetails?.permissions && workflowDetails?.data?.nextActions?.length > 0 && ( + + )} + {detail?.additionalDetails?.obpsDocuments && ( + + )} + {detail?.additionalDetails?.noc && ( + + )} + {detail?.additionalDetails?.scruntinyDetails && } + {detail?.additionalDetails?.buildingExtractionDetails && } + {detail?.additionalDetails?.subOccupancyTableDetails && ( + + )} + {detail?.additionalDetails?.documentsWithUrl && } + {detail?.additionalDetails?.documents && } + {detail?.additionalDetails?.taxHeadEstimatesCalculation && ( + + )} + {/* {detail?.isWaterConnectionDetails && } */} + {detail?.additionalDetails?.redirectUrl && ( +
+ + + {detail?.additionalDetails?.redirectUrl?.title} + + +
+ )} + {detail?.additionalDetails?.estimationDetails && } + {detail?.additionalDetails?.estimationDetails && } + + + ))} + {showTimeLine && workflowDetails?.data?.timeline?.length > 0 && ( + + {workflowDetails?.breakLineRequired === undefined ? : workflowDetails?.breakLineRequired ? : null} + {(workflowDetails?.isLoading || isDataLoading) && } + {!workflowDetails?.isLoading && !isDataLoading && ( + + + {/* {t("ES_APPLICATION_DETAILS_APPLICATION_TIMELINE")} */} + {t("WORKS_WORKFLOW_HISTORY")} + + {workflowDetails?.data?.timeline && workflowDetails?.data?.timeline?.length === 1 ? ( + + ) : ( + + {workflowDetails?.data?.timeline && + workflowDetails?.data?.timeline.map((checkpoint, index, arr) => { + return ( + + + + ); + })} + + )} + + )} + + )} + + + ); +} + +export default ApplicationDetailsContent; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js new file mode 100644 index 00000000000..9540495f32a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js @@ -0,0 +1,74 @@ +import React from "react"; +import { Toast } from "@egovernments/digit-ui-react-components"; + +function ApplicationDetailsToast({ t, showToast, closeToast, businessService }) { + if (businessService?.includes("NewTL") || businessService?.includes("TL") || businessService?.includes("EDITRENEWAL")) { + let label = ""; + switch (showToast?.action?.action) { + case "SENDBACK": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_SENDBACK_CHECKLIST_MESSAGE_HEAD"); + break; + case "FORWARD": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_FORWARD_SUCCESS_MESSAGE_MAIN"); + break; + case "APPROVE": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPROVAL_CHECKLIST_MESSAGE_HEAD"); + break; + case "SENDBACKTOCITIZEN": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_SENDBACK_TOCITIZEN_CHECKLIST_MESSAGE_HEAD"); + break; + case "REJECT": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPROVAL_REJ_MESSAGE_HEAD"); + break; + case "RESUBMIT": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPLICATION_RESUBMIT_SUCCESS_MESSAGE_MAIN"); + break; + case "CANCEL": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_TL_CANCELLED_MESSAGE_HEAD"); + break; + default: + label = showToast?.key === "error" ? showToast?.error?.message : t(`ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`); + } + return {showToast && }; + } else if (businessService?.includes("BPA") || businessService?.includes("BPA_LOW") || businessService?.includes("BPA_OC")) { + const getMessage = (messages = []) => { + let returnValue = messages[0]; + if(messages?.length == 2) returnValue = businessService?.includes("BPA_OC") ? t(messages[1]) : t(messages [0]); + else returnValue = t(messages[0]); + return returnValue; + } + let label = ""; + switch (showToast?.action?.action) { + case "REVOCATE": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_REVOCATED_MESSAGE_HEAD", "BPA_APPROVAL_OC_REVOCATED_MESSAGE_HEAD"]); + break; + case "VERIFY_AND_FORWARD": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_FORWARD_SUCCESS_MESSAGE_MAIN"]); + break; + case "SEND_BACK_TO_CITIZEN": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_SENDBACK_SUCCESS_MESSAGE_MAIN"]); + break; + case "APPROVE": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_CHECKLIST_MESSAGE_HEAD"]); + break; + case "REJECT": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_REJECTED_MESSAGE_HEAD", "BPA_OC_APPROVAL_REJECTED_MESSAGE_HEAD"]); + break; + case "FORWARD": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_FORWARD_SUCCESS_MESSAGE_MAIN"]); + break; + case "SEND_BACK_FOR_DOCUMENT_VERIFICATION": + case "SEND_BACK_FOR_FIELD_INSPECTION": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_SENDBACK_SUCCESS_MESSAGE_MAIN"]); + break; + default: + label = showToast?.key === "error" ? showToast?.error?.message : t(`ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`); + } + return {showToast && }; + } else { + const label = showToast?.key === "error" ? showToast?.error?.message : `ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`; + return {showToast && }; + } +} + +export default ApplicationDetailsToast; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js new file mode 100644 index 00000000000..e95b9e038cd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js @@ -0,0 +1,54 @@ +import { Card, ButtonSelector, CardText, CardSubHeader, Modal, CardSectionHeader, Row } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useTranslation } from "react-i18next"; + +const Close = () => ( + + + + + ); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); + }; + +function ApplicationDetailsWarningPopup({ action,workflowDetails,businessService,isWarningPop,closeWarningPopup }) { +const { t } = useTranslation(); +const isMobile = window.Digit.Utils.browser.isMobile(); +return ( + + {t("PT_DUES_ARE_PENDING")}} + headerBarEnd={ + { + closeWarningPopup(); + }} + /> + } + hideSubmit={true} + isDisabled={false} + popupStyles={isMobile ? {} : { width: "29%", marginTop: "auto" }} + > + +
+

{t("PT_YOU_HAVE")} ₹{action?.AmountDueForPay} {t("PT_DUE_WARNING_MSG2")}

+
+ +
+ + window.location.assign(`${window.location.origin}${action?.redirectionUrl?.pathname}`)} style={{ marginLeft: "10px" }} /> +
+
+
+ ) +
+) +} + +export default ApplicationDetailsWarningPopup; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js new file mode 100644 index 00000000000..9a1febe081b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js @@ -0,0 +1,234 @@ +import React, { useEffect, useState } from "react"; +import { + CardLabel, + Dropdown, + LabelFieldPair, + MultiUploadWrapper, + CardSubHeader +} from "@egovernments/digit-ui-react-components"; +import DocumentsPreview from "./DocumentsPreview"; + +const BPADocuments = ({ t, formData, applicationData, docs, bpaActionsDetails }) => { + const applicationStatus = applicationData?.status || ""; + const actions = bpaActionsDetails?.data?.nextActions || []; + const stateId = Digit.ULBService.getStateId(); + const [documents, setDocuments] = useState(formData?.documents?.documents || []); + const [error, setError] = useState(null); + const [bpaTaxDocuments, setBpaTaxDocuments] = useState([]); + const [enableSubmit, setEnableSubmit] = useState(true) + const [checkRequiredFields, setCheckRequiredFields] = useState(false); + const [checkEnablingDocs, setCheckEnablingDocs] = useState(false); + + const { isLoading: bpaDocsLoading, data: bpaDocs } = Digit.Hooks.obps.useMDMS(stateId, "BPA", ["DocTypeMapping"]); + const { isLoading: commonDocsLoading, data: commonDocs } = Digit.Hooks.obps.useMDMS(stateId, "common-masters", ["DocumentType"]); + + useEffect(() => { + let filtredBpaDocs = []; + if (bpaDocs?.BPA?.DocTypeMapping) { + // filtredBpaDocs = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == "INPROGRESS")) + filtredBpaDocs = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == applicationData?.status ? applicationData?.status : "INPROGRESS" && data.RiskType == applicationData?.riskType && data.ServiceType == applicationData?.additionalDetails?.serviceType && data.applicationType == applicationData?.additionalDetails?.applicationType)) + } + let documentsList = []; + filtredBpaDocs?.[0]?.docTypes?.forEach(doc => { + let code = doc.code; doc.dropdownData = []; doc.uploadedDocuments = []; + commonDocs?.["common-masters"]?.DocumentType?.forEach(value => { + let values = value.code.slice(0, code.length); + if (code === values) { + doc.hasDropdown = true; + value.i18nKey = value.code; + doc.dropdownData.push(value); + } + }); + doc.uploadedDocuments[0] = {}; + doc.uploadedDocuments[0].values = []; + docs?.[0]?.values?.map(upDocs => { + if (code === `${upDocs?.documentType?.split('.')[0]}.${upDocs?.documentType?.split('.')[1]}`) { + doc.uploadedDocuments[0].values.push(upDocs) + } + }) + documentsList.push(doc); + }); + sessionStorage.setItem("BPA_DOCUMENTS", JSON.stringify(documentsList)); + setBpaTaxDocuments(documentsList); + + }, [!bpaDocsLoading, !commonDocsLoading]); + + useEffect(() => { + let count = 0; + bpaTaxDocuments.map(doc => { + let isRequired = false; + documents.map(data => { + if (doc.required && doc.code == `${data.documentType.split('.')[0]}.${data.documentType.split('.')[1]}`) { + isRequired = true; + } + }); + if (!isRequired && doc.required) { + count = count + 1; + } + }); + if ((count == "0" || count == 0) && documents.length > 0) setEnableSubmit(false); + else setEnableSubmit(true); + }, [documents, checkRequiredFields]) + + useEffect(() => { + if ( applicationStatus === "DOC_VERIFICATION_INPROGRESS" && actions?.length > 0 ) setCheckEnablingDocs(true); + else setCheckEnablingDocs(false); + }, [applicationData, bpaActionsDetails]) + + return ( +
+ {bpaTaxDocuments?.map((document, index) => { + return ( +
+ +
+ ); + })} +
+ ); +} + +function SelectDocument({ + t, + document: doc, + setDocuments, + error, + setError, + documents, + setCheckRequiredFields, + index, + applicationStatus, + actions, + bpaTaxDocuments, + checkEnablingDocs +}) { + + const filteredDocument = documents?.filter((item) => item?.documentType?.includes(doc?.code))[0]; + const tenantId = Digit.ULBService.getStateId(); + const [selectedDocument, setSelectedDocument] = useState( + filteredDocument + ? { ...filteredDocument, active: true, code: filteredDocument?.documentType, i18nKey: filteredDocument?.documentType } + : doc?.dropdownData?.length === 1 + ? doc?.dropdownData[0] + : {} + ); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(() => filteredDocument?.fileStoreId || null); + const [selectArrayFiles, SetSelectArrayFiles] = useState([]); + const handleSelectDocument = (value) => setSelectedDocument(value); + const allowedFileTypes = /(.*?)(jpg|jpeg|png|image|pdf)$/i; + + function selectfiles(e) { + e && setFile(e.file); + } + + + useEffect(() => { + if (selectedDocument?.code) { + setDocuments((prev) => { + const filteredDocumentsByDocumentType = prev?.filter((item) => item?.documentType !== selectedDocument?.code); + if (uploadedFile?.length === 0 || uploadedFile === null) return filteredDocumentsByDocumentType; + const filteredDocumentsByFileStoreId = filteredDocumentsByDocumentType?.filter((item) => item?.fileStoreId !== uploadedFile); + return [ + ...filteredDocumentsByFileStoreId, + { + documentType: selectedDocument?.code, + fileStoreId: uploadedFile, + documentUid: uploadedFile, + fileName: file?.name || "", + id: documents ? documents.find(x => x.documentType === selectedDocument?.code)?.id : undefined, + }, + ]; + }); + } + }, [uploadedFile, selectedDocument]); + + useEffect(() => { + (async () => { + if (selectArrayFiles.length > 0) { + sessionStorage.removeItem("BPA_DOCUMENTS"); + doc.newUploadedDocs = []; + selectArrayFiles.map(newDoc => { + if (selectedDocument?.code) { + doc.newUploadedDocs.push({ + documentType: selectedDocument?.code, + fileStoreId: newDoc?.fileStoreId?.fileStoreId, + documentUid: newDoc?.fileStoreId?.fileStoreId, + tenantId: newDoc?.fileStoreId?.tenantId + }); + } + }) + bpaTaxDocuments[index] = doc; + sessionStorage.setItem("BPA_DOCUMENTS", JSON.stringify(bpaTaxDocuments)); + } + })(); + }, [selectArrayFiles, selectedDocument]); + + useEffect(() => { + (async () => { + + })(); + }, [file]); + + const getData = (index, state) => { + let data = Object.fromEntries(state); + let newArr = Object.values(data); + if (Object.keys(data).length !== 0) SetSelectArrayFiles(newArr); + selectfiles(newArr[newArr.length - 1]); + } + + return ( +
+ {`${t(doc?.code)}`} + {doc?.uploadedDocuments?.length && } + { + checkEnablingDocs ? +
+ + {doc?.required ? `${t(doc?.code)}* ` : `${t(doc?.code)}`} + + + + +
+ getData(index, e)} + t={t} + allowedFileTypesRegex={allowedFileTypes} + allowedMaxSizeInMB={5} + acceptFiles= "image/*, .pdf, .png, .jpeg, .jpg" + /> +
+
+
: null + } +
+ ); +} + +export default BPADocuments; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js new file mode 100644 index 00000000000..dfd57683def --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js @@ -0,0 +1,49 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { CardSubHeader, PDFSvg } from "@egovernments/digit-ui-react-components"; + +function DocumentsPreview({ documents, svgStyles = {}, isSendBackFlow = false, isHrLine = false, titleStyles }) { + const { t } = useTranslation(); + const isStakeholderApplication = window.location.href.includes("stakeholder"); + + return ( +
+ {!isStakeholderApplication && documents?.map((document, index) => ( + + {document?.title ? {t(document?.title)} : null} +
+ {document?.values && document?.values.length > 0 ? document?.values?.map((value, index) => ( + +
+ +
+

{t(value?.title)}

+ {isSendBackFlow ? value?.documentType?.includes("NOC") ?

{t(value?.documentType.split(".")[1])}

:

{t(value?.documentType)}

: ""} +
+ )) : !(window.location.href.includes("citizen")) &&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} +
+ {isHrLine && documents?.length != index + 1 ?
: null} +
+ ))} + {isStakeholderApplication && documents?.map((document, index) => ( + + {document?.title ? {t(document?.title)} : null} +
+ {document?.values && document?.values.length > 0 ? document?.values?.map((value, index) => ( + +
+

{t(value?.title)}

+ {value?.docInfo ?
{`${t(value?.docInfo)}`}
: null} + +

{`${t(value?.title)}`}

+
+
+ )) : !(window.location.href.includes("citizen")) &&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} +
+
+ ))} +
+ ); +} + +export default DocumentsPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js new file mode 100644 index 00000000000..12e2f64fac6 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js @@ -0,0 +1,34 @@ +import React from "react"; +import { InfoBannerIcon } from "@egovernments/digit-ui-react-components"; + +const EyeSvgINdex = ({ style }) => { + return + + + + + +} +const InfoDetails = ({ t, userType = false, infoBannerLabel = "", infoClickLable = "", infoClickInfoLabel = "", infoClickInfoLabel1 = "" }) => { + userType = userType || Digit.SessionStorage.get("userType"); + return ( + +
+
+
+ +

{t(infoBannerLabel)}

+
+ {`${t(infoClickLable)} `} + + {` ${t(infoClickInfoLabel)}`} +
+ {` ${t(infoClickInfoLabel1)}`} +
+
+
+
+ ); +}; + +export default InfoDetails; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js new file mode 100644 index 00000000000..a824b05a435 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js @@ -0,0 +1,49 @@ +import { StatusTable, Row, CardHeader, CardSectionHeader } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import DocumentsPreview from "./DocumentsPreview"; + +const getDocuments = (fiDocuments) => { + const returnDocuments = [{ + title: "BPA_DOCUMENT_DETAILS_LABEL", + values: fiDocuments?.map(doc => ({ + title: doc?.documentType?.replaceAll('.', '_'), + documentType: doc?.documentType, + documentUid: doc?.documentUid, + fileStoreId: doc?.fileStoreId, + id: doc?.id, + url: doc?.url + })) + }]; + return returnDocuments; +}; + +function InspectionReport({ fiReport, isCitizen=false }) { + const { t } = useTranslation(); + + return ( + +
+ {isCitizen?{`${t(`BPA_FI_REPORT`)}`}: + {`${t(`BPA_FI_REPORT`)}`}} + {fiReport.map((fiData, index) => +
+ + {fiReport?.length == 1 ? `${t(`BPA_FI_REPORT`)}` : `${t(`BPA_FI_REPORT`)} - ${index + 1}`} + + + {fiData?.questions?.length && + fiData?.questions?.map((qstn) => +
+ + +
)} + +
+
)} +
+
+ ); +} + +export default InspectionReport; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js new file mode 100644 index 00000000000..1581744f756 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js @@ -0,0 +1,202 @@ +import React, { useEffect, useState } from "react"; +import { + CardLabel, + MultiUploadWrapper, + StatusTable, + Row, + LabelFieldPair +} from "@egovernments/digit-ui-react-components"; +import DocumentsPreview from "./DocumentsPreview"; + +function SelectDocument({ + t, + document: doc, + setNocDocuments, + setError, + nocDocuments +}) { + const filteredDocument = nocDocuments?.filter((item) => item?.documentType?.includes(doc?.code))[0]; + const tenantId = Digit.ULBService.getStateId(); + const [selectedDocument, setSelectedDocument] = useState(); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(() => filteredDocument?.fileStoreId || null); + const handleSelectDocument = (value) => setSelectedDocument(value); + const allowedFileTypes = /(.*?)(jpg|jpeg|png|image|pdf)$/i; + + function selectfile(e) { + e && setFile(e.file); + } + + useEffect(() => { + if (doc?.dropdownData?.[0]?.code) { + setNocDocuments((prev) => { + const filteredDocumentsByDocumentType = prev?.filter((item) => item?.documentType !== doc?.dropdownData?.[0]?.code); + + if (uploadedFile?.length === 0 || uploadedFile === null) { + return filteredDocumentsByDocumentType; + } + + const filteredDocumentsByFileStoreId = filteredDocumentsByDocumentType?.filter((item) => item?.fileStoreId !== uploadedFile); + return [ + ...filteredDocumentsByFileStoreId, + { + documentType: doc?.dropdownData?.[0].code, + fileStoreId: uploadedFile, + documentUid: uploadedFile, + fileName: file?.name || "", + }, + ]; + }); + } + }, [uploadedFile]); + + + useEffect(() => { + (async () => { + setError(null); + if (file) { + const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { + setError(t(`NOT_SUPPORTED_FILE_TYPE`)) + } else { + try { + setUploadedFile(null); + const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + const getData =(state) => { + let data = Object.fromEntries(state); + let newArr = Object.values(data); + selectfile(newArr[newArr.length-1]); + } + + return ( +
+ + {doc?.required ? `${t("TL_BUTTON_UPLOAD FILE")}*` : `${t("TL_BUTTON_UPLOAD FILE")}`} +
+ getData(e)} + t={t} + allowedFileTypesRegex={allowedFileTypes} + allowedMaxSizeInMB={5} + acceptFiles="image/*, .pdf, .png, .jpeg, .jpg" + /> +
+
+
+ ); +} +const NOCDocuments = ({ t, noc, docs, isNoc, applicationData,NOCdata, bpaActionsDetails }) => { + const tenantId = Digit.ULBService.getStateId(); + const stateId = Digit.ULBService.getStateId(); + const bpaApplicationStatus = applicationData?.status || ""; + const actions = bpaActionsDetails?.data?.nextActions || []; + const { isLoading: nocDocsLoading, data: nocDocs } = Digit.Hooks.obps.useMDMS(stateId, "NOC", ["DocumentTypeMapping"], { enabled: isNoc }); + const { isLoading: bpaDocsLoading, data: bpaDocs } = Digit.Hooks.obps.useMDMS(stateId, "BPA", ["DocTypeMapping"], { enabled: !isNoc }); + const { isLoading: commonDocsLoading, data: commonDocs } = Digit.Hooks.obps.useMDMS(stateId, "common-masters", ["DocumentType"]); + const [commonDocMaping, setCommonDocMaping] = useState([]); + const [nocTaxDocuments, setNocTaxDocuments] = useState([]); + const [checkEnablingDocs, setCheckEnablingDocs] = useState(false); + const [nocDocuments, setNocDocuments] = Digit.Hooks.useSessionStorage(noc?.nocType, []); + const [error, setError] = useState(null); + const isEmployee = window.location.href.includes("/employee/") + + useEffect(() => { + setCommonDocMaping(commonDocs?.["common-masters"]?.DocumentType); + }, [commonDocs]); + + useEffect(() => { + let documents = []; + let filteredData + if (isNoc) { + filteredData = nocDocs?.NOC?.DocumentTypeMapping?.filter((data => { + return data?.applicationType === noc?.applicationType && data?.nocType === noc?.nocType + })); + } + else { + filteredData = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == applicationData?.status && data.RiskType == applicationData?.riskType && data.ServiceType == applicationData?.additionalDetails?.serviceType && data.applicationType == applicationData?.additionalDetails?.applicationType)) + } + if (filteredData?.[0]?.docTypes?.[0]) { + filteredData[0].docTypes[0].nocType = filteredData[0].nocType; + filteredData[0].docTypes[0].additionalDetails = { + submissionDetails: noc?.additionalDetails, + applicationStatus: noc?.applicationStatus, + appNumberLink: noc?.applicationNo, + nocNo: noc?.nocNo + } + documents.push(filteredData[0].docTypes[0]); + } + let documentsList = []; + if (documents && documents.length > 0) { + documents.map((doc) => { + let code = doc.documentType; + let nocType = doc.nocType; + doc.dropdownData = []; + commonDocMaping?.forEach((value) => { + let values = value.code.slice(0, code?.length); + if (code === values) { + doc.hasDropdown = true; + doc.dropdownData.push(value); + } + }); + documentsList.push(doc); + }); + setNocTaxDocuments(documentsList); + } + }, [nocDocs, commonDocMaping]); + + useEffect(() => { + if (bpaApplicationStatus === 'NOC_VERIFICATION_INPROGRESS' && actions?.length > 0) setCheckEnablingDocs(true); + else setCheckEnablingDocs(false); + }, [applicationData, bpaActionsDetails]) + + return ( +
+ + + {NOCdata && NOCdata.map((noc,index) => { + if (noc?.value) { + if (noc?.field == "STATUS") { + return + } else { + return + } + } + })} + + + {checkEnablingDocs && nocTaxDocuments?.map((document, index) => { + return ( + + ); + })} +
+ ); +} + +export default NOCDocuments; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js new file mode 100644 index 00000000000..89007789722 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js @@ -0,0 +1,87 @@ +import { CheckBox, LinkButton, TextInput,Close, CardSubHeader } from "@egovernments/digit-ui-react-components"; +import React, { useEffect, useState } from "react"; + +const PermissionCheck = ({ permissions, t }) => { + const [approvalChecks, setApprovalChecks, clearApprovals] = Digit.Hooks.useSessionStorage("OBPS_APPROVAL_CHECKS", permissions?.map(permission => ({ label: permission, checked: false }))); //useState(() => permissions?.map(permission => ({ label: permission, checked: false }))) + const [newApprovals, setNewApprovals, clearNewApprovals] = Digit.Hooks.useSessionStorage('OBPS_NEW_APPROVALS', []); + + useEffect(() => { + return () => { + Digit.SessionStorage.del("OBPS_NEW_APPROVALS"); + Digit.SessionStorage.del("OBPS_APPROVAL_CHECKS"); + } + }, []) + + const handleAdd = () => { + setNewApprovals([...newApprovals, { label: '' }]); + } + + const handleRemove = (index) => { + const values = [...newApprovals]; + values.splice(index, 1); + setNewApprovals([...values]); + } + + const handleChange = (event, index) => { + setNewApprovals(() => { + return newApprovals?.map((approval, id) => { + if (index === id) { + return { + label: event?.target?.value, + } + } + return approval; + }) + }) + } + + const handleCheck = (event, label, index) => { + const isChecked = event.target.checked; + setApprovalChecks(() => { + return approvalChecks?.map((approval, id) => { + if (index === id) { + return { + ...approval, + checked: isChecked + } + } + return approval; + }) + }) + } + + return ( +
+ {t("BPA_PERMIT_CONDITIONS")} + {approvalChecks?.map((permission, index) => ( + handleCheck(event, permission?.label, index))} + isLabelFirst={true} + index={index} + /> + ))} + {newApprovals?.map((approval, index) => ( +
handleChange(event, index)} textInputStyle={{maxWidth: "830px", width: "830px"}} placeholder={"Enter permit conditions.........."} /> + { + + + +
+ } + style={{ }} + onClick={(e) => handleRemove(index)} + />} +
+ ))} + +
+ ) +} + +export default PermissionCheck; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js new file mode 100644 index 00000000000..ea8cd1eb104 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js @@ -0,0 +1,83 @@ +import React, { useState, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { CardSubHeader, PDFSvg } from "@egovernments/digit-ui-react-components"; + +// const PDFSvg = ({ width = 34, height = 34, style, viewBox = "0 0 34 34" }) => ( +// +// +// +// ); + +function PropertyDocuments({ documents, svgStyles = {}, isSendBackFlow=false }) { + const { t } = useTranslation(); + const [filesArray, setFilesArray] = useState(() => [] ); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const [pdfFiles, setPdfFiles] = useState({}); + + useEffect(() => { + let acc = []; + documents?.forEach((element, index, array) => { + acc = [...acc, ...(element.values?element.values:[])]; + }); + setFilesArray(acc?.map((value) => value?.fileStoreId)); + }, [documents]); + + useEffect(() => { + if (filesArray?.length && documents?.[0]?.BS === "BillAmend") { + Digit.UploadServices.Filefetch(filesArray, Digit.ULBService.getCurrentTenantId()).then((res) => { + setPdfFiles(res?.data); + }); + } + else if(filesArray?.length) + { + Digit.UploadServices.Filefetch(filesArray, Digit.ULBService.getStateId()).then((res) => { + setPdfFiles(res?.data); + }); + } + + }, [filesArray]); + + const checkLocation = window.location.href.includes("employee/tl") || window.location.href.includes("/obps") || window.location.href.includes("employee/ws"); + const isStakeholderApplication = window.location.href.includes("stakeholder"); + + return ( +
+ {!isStakeholderApplication && documents?.map((document, index) => ( + + {document?.title ? {t(document?.title)}: null} +
+ {document?.values && document?.values.length>0 ? document?.values?.map((value, index) => ( + +
+ +
+

{t(value?.title)}

+ {isSendBackFlow? value?.documentType?.includes("NOC")?

{t(value?.documentType.split(".")[1])}

:

{t(value?.documentType)}

:""} +
+ )):!(window.location.href.includes("citizen"))&&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} +
+
+ ))} + {isStakeholderApplication && documents?.map((document, index) => ( + + {document?.title ? {t(document?.title)} : null} +
+ {document?.values && document?.values.length>0 ? document?.values?.map((value, index) => ( + +
+

{t(value?.title)}

+ {value?.docInfo ?
{`${t(value?.docInfo)}`}
: null} + + {/*
{decodeURIComponent(pdfFiles[value.fileStoreId]?.split(",")[0].split("?")[0].split("/").pop().slice(13))}
*/} +

{`${t(value?.title)}`}

+
+
+ )):!(window.location.href.includes("citizen"))&&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} +
+
+ ))} +
+ ); +} + +export default PropertyDocuments; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js new file mode 100644 index 00000000000..c4cde76709f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js @@ -0,0 +1,39 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { StatusTable, Row, BreakLine } from "@egovernments/digit-ui-react-components"; + +function PropertyEstimates({ taxHeadEstimatesCalculation }) { + const { taxHeadEstimates } = taxHeadEstimatesCalculation; + const { t } = useTranslation(); + + return ( +
+ + + + {taxHeadEstimates?.map((estimate, index) => { + return ( + + ); + })} + + + +
+ ); +} + +export default PropertyEstimates; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js new file mode 100644 index 00000000000..4f33bbdcff4 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js @@ -0,0 +1,49 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; + +function PropertyFloors({ floors }) { + const { t } = useTranslation(); + + return ( + + {floors.map((floor) => ( +
+ {t(floor?.title)} + {floor?.values?.map((value, index) => { + return ( + + + {t(value.title)} + + +
+ {value?.values?.map((value, index) => { + if (value.map === true && value.value !== "N/A") { + return } />; + } + return ( + + ); + })} +
+
+
+ ); + })} +
+ ))} +
+ ); +} + +export default PropertyFloors; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js new file mode 100644 index 00000000000..dac9f41c79b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js @@ -0,0 +1,94 @@ +import { CardSubHeader, Row, StatusTable } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useTranslation } from "react-i18next"; + +function PropertyOwners({ owners }) { + const { t } = useTranslation(); + + const checkLocation = true; + const checkOwnerLength = owners?.length || 1; + let cardStyles = { marginTop: "19px" }; + let statusTableStyles = { position: "relative", padding: "8px" }; + let rowContainerStyle = { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; + if (checkLocation && Number(checkOwnerLength) > 1) { + cardStyles = { + marginTop: "19px", + background: "#FAFAFA", + border: "1px solid #D6D5D4", + borderRadius: "4px", + padding: "8px", + lineHeight: "19px", + maxWidth: "600px", + minWidth: "280px", + }; + } else if (checkLocation && !(Number(checkOwnerLength) > 1)) { + cardStyles = { marginTop: "19px", lineHeight: "19px", maxWidth: "600px", minWidth: "280px" }; + statusTableStyles = { position: "relative", marginTop: "19px" }; + } + + if (window.location.href.includes("obps")) { + cardStyles = { ...cardStyles, maxWidth: "950px" }; + cardStyles = { ...cardStyles, maxWidth: "950px" }; + rowContainerStyle = {}; + } + + return ( + + {owners.map((owner, index) => ( +
+ {/* TODO, Later will move to classes */} + 1 + ? { marginBottom: "8px", paddingBottom: "9px", color: "#0B0C0C", fontSize: "16px", lineHeight: "19px" } + : { marginBottom: "8px", color: "#505A5F", fontSize: "24px" } + } + > + {checkLocation && Number(checkOwnerLength) > 1 ? `${t(owner?.title)} ${index + 1}` : t(owner?.title)} + + + +
+ {owner?.values?.map((value, index) => { + if (value.map === true && value.value !== "N/A") { + return } />; + } + return ( + + + + ); + })} +
+
+
+ ))} +
+ ); +} + +export default PropertyOwners; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js new file mode 100644 index 00000000000..0f226935c5b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js @@ -0,0 +1,10 @@ +import React from "react"; + +const Reason = ({ headComment, otherComment }) => ( +
+

{headComment}

+

{otherComment}

+
+); + +export default Reason; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js new file mode 100644 index 00000000000..bde27623ba8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js @@ -0,0 +1,46 @@ +import { StatusTable, Row, PDFSvg, CardLabel, CardSubHeader } from "@egovernments/digit-ui-react-components"; +import React, { Fragment } from "react"; +import { useTranslation } from "react-i18next"; + +const ScruntinyDetails = ({ scrutinyDetails, paymentsList=[] }) => { + const { t } = useTranslation(); + let count = 0; + const getTextValues = (data) => { + if (data?.value && data?.isTransLate) return {t(data?.value)}; + else if (data?.value && data?.isTransLate) return t(data?.value); + else if (data?.value) return data?.value; + else t("NA"); + } + return ( + + {!scrutinyDetails?.isChecklist &&
+ +
+ {scrutinyDetails?.values?.map((value, index) => { + if (value?.isUnit) return + else if (value?.isHeader && !value?.isUnit) return {t(value?.title)} + else if (value?.isSubTitle && !value?.isUnit) return {t(value?.title)} + else return + })} + {scrutinyDetails?.permit?.map((value,ind) => { + return {value?.title} + })} +
+
+ {scrutinyDetails?.scruntinyDetails?.map((report, index) => { + return ( + + + +

{t(report?.text)}

+
+ ) + })} +
+
+
} +
+ ) +} + +export default ScruntinyDetails; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js new file mode 100644 index 00000000000..e266bed6be2 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js @@ -0,0 +1,126 @@ +import React, { Fragment, useMemo } from "react"; +import { Table, StatusTable, Row, CardSubHeader, CardSectionHeader } from "@egovernments/digit-ui-react-components"; +import { useTranslation } from "react-i18next"; + +const SubOccupancyTable = ({ edcrDetails, applicationData }) => { + const { t } = useTranslation(); + const isMobile = window.Digit.Utils.browser.isMobile(); + + const tableHeader = [ + { + name: "BPA_TABLE_COL_FLOOR", + id: "Floor", + }, + { + name: "BPA_TABLE_COL_LEVEL", + id: "Level", + }, + { + name: "BPA_TABLE_COL_OCCUPANCY", + id: "Occupancy", + }, + { + name: "BPA_TABLE_COL_BUILDUPAREA", + id: "BuildupArea", + }, + { + name: "BPA_TABLE_COL_FLOORAREA", + id: "FloorArea", + }, + { + name: "BPA_TABLE_COL_CARPETAREA", + id: "CarpetArea", + } + ] + + const accessData = (plot) => { + const name = plot; + return (originalRow, rowIndex, columns) => { + return originalRow[name]; + } + } + + + const tableColumns = useMemo( + () => { + return tableHeader.map((ob) => ({ + Header: t(`${ob.name}`), + accessor: accessData(ob.id), + id: ob.id + })); + }); + + function getFloorData(block) { + let floors = []; + block?.building?.floors.map((ob) => { + floors.push({ + Floor: t(`BPA_FLOOR_NAME_${ob.number}`), + Level: ob.number, + Occupancy: t(`${ob.occupancies?.[0]?.type}`), + BuildupArea: ob.occupancies?.[0]?.builtUpArea, + FloorArea: ob.occupancies?.[0]?.floorArea || 0, + CarpetArea: ob.occupancies?.[0]?.CarpetArea || 0, + key: t(`BPA_FLOOR_NAME_${ob.number}`), + }); + }); + return floors; + } + + const stringReplaceAll = (str = "", searcher = "", replaceWith = "") => { + if (searcher == "") return str; + while (str.includes(searcher)) { + str = str.replace(searcher, replaceWith); + } + return str; + }; + + function getSubOccupancyValues(index) { + let values = applicationData?.landInfo?.unit; + let returnValue = ""; + if (values?.length > 0) { + let splitArray = values[index]?.usageCategory?.split(','); + if (splitArray?.length) { + const returnValueArray = splitArray.map(data => data ? `${t(`BPA_SUBOCCUPANCYTYPE_${stringReplaceAll(data?.toUpperCase(), "-", "_")}`)}` : "NA"); + returnValue = returnValueArray.join(', ') + } + } + return returnValue ? returnValue : "NA"; + } + + return ( + +
+ + {edcrDetails?.values?.map((value, index) => { + if (value?.isHeader) return {t(value?.title)} + else return + })} + + + {edcrDetails?.subOccupancyTableDetails?.[0]?.value?.planDetail?.blocks.map((block, index) => ( +
0 ? {marginBottom: "30px", background: "#FAFAFA", border: "1px solid #D6D5D4", padding: "8px", borderRadius: "4px", maxWidth: "950px", minWidth: "280px"} : {marginBottom: "30px"}}> + {t("BPA_BLOCK_SUBHEADER")} {index + 1} + + + +
+ { return { style: {} } }} + /> + + ))} + + + ) +} + +export default SubOccupancyTable; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js new file mode 100644 index 00000000000..08b89e68419 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js @@ -0,0 +1,77 @@ +import { EditIcon } from '@egovernments/digit-ui-react-components'; +import React from 'react' +import { useTranslation } from "react-i18next"; +import { useHistory } from 'react-router-dom'; + +const SubWorkTableDetails = ({data}) => { + const { t } = useTranslation(); + const history = useHistory(); + const getStyles = (index) => { + let obj = {} + switch (index) { + case 1: + obj = { "width": "1vw" } + break; + case 2: + obj = { "width": "60vw" } + break; + case 3: + obj = { "width": "20vw" } + break; + case 4: + obj = { "width": "10vw" } + break; + default: + obj = { "width": "1vw" } + break; + } + return obj + } + const renderHeader = (headers) => { + return headers?.map((key, index) => { + return + }) + } + + const renderBody = (rows) => { + return rows?.map((row, index) => { + return + + + {row[1] === t("WORKS_TOTAL_AMT") + ? + : } + {row[3] && } + {/* */} + + }) + } + + return ( +
{t(key)}
{row[0]} { row[1] === t("WORKS_TOTAL_AMT") ?
{row[1]}
:
{row[1]}
}
{row[2]}
{row[2]}
+
history.push( + { + pathname: `/digit-ui/employee/contracts/create-contract?estimateNumber=${data?.state?.estimateNumber}&task=${data?.state?.estimateDetails[index]?.name}&subEstimate=${data?.state?.estimateDetails[index]?.estimateDetailNumber}`, + state:{index, data} + } + )}> + {row[3]} +
+
{showDelete() && removeRow(row)}>}
+ + {renderHeader(data?.headers)} + + + {renderBody(data?.tableRows)} + {/* + + + + + */} + +
+ ) +} + +export default SubWorkTableDetails \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js new file mode 100644 index 00000000000..e5fbcde20cd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js @@ -0,0 +1,34 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { TelePhone, DisplayPhotos, UnMaskComponent } from "@egovernments/digit-ui-react-components"; +import Reason from "./Reason"; + +const TLCaption = ({ data,OpenImage,privacy={}}) => { + + const { t } = useTranslation(); + return ( +
+ {data.date &&

{data.date}

} +

{data.name}

+ {data.mobileNumber && + +

    

+ +
} + {data.source &&

{t("ES_APPLICATION_DETAILS_APPLICATION_CHANNEL_" + data.source.toUpperCase())}

} + {data.comment && } + {data?.wfComment ?
{data?.wfComment?.map( e => +
+

{t("WF_COMMON_COMMENTS")}

+

{e}

+
+ )}
: null} + {data?.thumbnailsToShow?.thumbs?.length > 0 ?
+

{t("CS_COMMON_ATTACHMENTS")}

+ {OpenImage(src, index,data?.thumbnailsToShow)}} /> +
: null} +
+ ); +}; + +export default TLCaption; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js new file mode 100644 index 00000000000..536a2ce3eca --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js @@ -0,0 +1,52 @@ + +import React from "react"; +import { useTranslation } from "react-i18next"; +import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; + +function TLTradeAccessories({ units }) { + const { t } = useTranslation(); + return ( + + {units.map((unit, index) => ( + // TODO, Later will move to classes +
+ {`${t(unit?.title)} ${index + 1}`} + + +
+ {unit?.values?.map((value, index) => { + if (value.map === true && value.value !== "N/A") { + return } />; + } + return ( + + ); + })} +
+
+
+ ))} +
+ ); +} + +export default TLTradeAccessories; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js new file mode 100644 index 00000000000..bf1c1fbc780 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js @@ -0,0 +1,51 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; + +function TLTradeUnits({ units }) { + const { t } = useTranslation(); + return ( + + {units.map((unit, index) => ( + // TODO, Later will move to classes +
+ {`${t(unit?.title)} ${index + 1}`} + + +
+ {unit?.values?.map((value, index) => { + if (value.map === true && value.value !== "N/A") { + return } />; + } + return ( + + ); + })} +
+
+
+ ))} +
+ ); +} + +export default TLTradeUnits; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js new file mode 100644 index 00000000000..5608aeb2d2a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js @@ -0,0 +1,73 @@ +import React, { useState, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { CardSectionHeader, Modal, Row, StatusTable } from "@egovernments/digit-ui-react-components"; + +const ViewBreakup = ({ wsAdditionalDetails, workflowDetails }) => { + const { t } = useTranslation(); + const [popup, showPopUp] = useState(false); + const [breakUpData, setBreakUpData] = useState({}); + + const Heading = (props) => { + return

{props.label}

; + }; + + const Close = () => ( + + + + + ); + + const CloseBtn = (props) => { + return ( +
+ +
+ ); + }; + + const onPopupOpen = () => { + let breakupData = wsAdditionalDetails.additionalDetails.data || {}; + const sessionBillData = sessionStorage.getItem("Digit.ADHOC_BILL_ADD_REBATE_DATA"); + const sessionBillFormData = sessionBillData ? JSON.parse(sessionBillData) : {}; + if (sessionBillFormData?.value?.totalAmount) breakupData = sessionBillFormData?.value; + setBreakUpData(breakupData); + showPopUp(true); + } + + return ( + +
+ {wsAdditionalDetails?.additionalDetails?.isViewBreakup ?
onPopupOpen()} style={{ marginTop: "12px" }}> + {t("WS_PAYMENT_VIEW_BREAKUP")} +
: null + } + {popup && + } + headerBarEnd={ { showPopUp(false); }} />} + hideSubmit={true} + popupStyles={{ overflowY: "auto" }} //maxHeight: "calc(100% - 90px)" + headerBarMainStyle={{ marginBottom: "0px" }} + popupModuleMianStyles={{ paddingTop: "0px" }} + > + { + {t("WS_APPLICATION_FEE_HEADER")} + {breakUpData?.billSlabData?.FEE?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} +
+ ₹{Number(breakUpData?.fee) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> + {t("WS_SERVICE_FEE_HEADER")} + {breakUpData?.billSlabData?.CHARGES?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} +
+ ₹{Number(breakUpData?.charge) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> + {breakUpData?.billSlabData?.TAX?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} +
+ ₹{Number(breakUpData?.totalAmount) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> +
} +
} +
+
+ ) +} + +export default ViewBreakup; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js new file mode 100644 index 00000000000..06814062d96 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js @@ -0,0 +1,399 @@ +import { StatusTable, Row, CardSubHeader } from "@egovernments/digit-ui-react-components"; +import React, { Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { getQueryStringParams } from "../../../ws/src/utils"; + +const cardSubHeaderStyles = () => { + // return { fontSize: "24px", padding: "0px", margin: "0px", color: "#505A5F" }; + return { fontSize: "24px", marginBottom: "16px", marginTop: "32px" }; +}; + +const cardDivStyles = () => { + return { + border: "1px solid #D6D5D4", + background: "#FAFAFA", + borderRadius: "4px", + padding: "10px 10px 0px 10px", + marginBottom: "10px", + display: "flex", + }; +}; + +const convertEpochToDate = (dateEpoch) => { + if (dateEpoch) { + const dateFromApi = new Date(dateEpoch); + let month = dateFromApi.getMonth() + 1; + let day = dateFromApi.getDate(); + let year = dateFromApi.getFullYear(); + month = (month > 9 ? "" : "0") + month; + day = (day > 9 ? "" : "0") + day; + return `${day}/${month}/${year}`; + } else { + return null; + } +}; + +const WSAdditonalDetails = ({ wsAdditionalDetails, oldValue }) => { + const { t } = useTranslation(); + let filters = getQueryStringParams(location.search); + const serviceType = filters?.service; + const isModify = filters?.mode; + + const oldValueData = oldValue?.[1]; + + const stringReplaceAll = (str = "", searcher = "", replaceWith = "") => { + if (searcher == "") return str; + while (str.includes(searcher)) { + str = str.replace(searcher, replaceWith); + } + return str; + }; + + const renderSWConnectionDetails = () => { + return ( +
+ {oldValueData?.connectionType ? ( + + ) : ( +
{"NA"}
+ )} + + {oldValueData?.noOfWaterClosets ? ( + + ) : ( +
{"NA"}
+ )} + {oldValueData?.noOfToilets ? ( + + ) : ( +
{"NA"}
+ )} +
+ ); + }; + + const renderWSConnectionDetails = () => { + return ( +
+ {oldValueData?.connectionType && ( )} + {oldValueData?.noOfTaps && ( )} + {oldValueData?.waterSource && ( )} + {oldValueData?.pipeSize && ( )} + {oldValueData?.waterSource && ( )} +
+ ); + }; + + const renderSWPlumberDetails = () => { + return ( +
+ {oldValueData?.additionalDetails?.detailsProvidedBy !== wsAdditionalDetails?.additionalDetails?.plumberDetails[0]?.value && + oldValueData?.additionalDetails?.detailsProvidedBy !== null ? ( + + ) : ( +
{"NA"}
+ )} + {oldValueData?.plumberInfo ? ( + + ) : ( +
{"NA"}
+ )} + {oldValueData?.plumberInfo ? ( + + ) : ( +
{"NA"}
+ )} + {oldValueData?.plumberInfo ? ( + + ) : ( +
{"NA"}
+ )} +
+ ); + }; + + const renderWSPlumberDetails = () => { + return ( +
+ {oldValueData?.additionalDetails?.detailsProvidedBy !== wsAdditionalDetails?.additionalDetails?.plumberDetails[0]?.value ? ( + + ) : ( +
{"NA"}
+ )} +
+ ); + }; + + const renderSWRoadCuttingDetails = () => { + { + oldValueData?.roadCuttingInfo?.map((info) => { + return ( +
+ + +
+ ); + }); + } + }; + + const renderSWActivationDetails = () => { + return ( +
+ {oldValueData?.connectionExecutionDate ? ( + + ) : ( +
{"NA"}
+ )} +
+ ); + }; + + const renderWSActivationDetails = () => { + return ( +
+ {oldValueData?.meterId && ( )} + {oldValueData?.additionalDetails?.initialMeterReading && ( )} + {oldValueData?.meterInstallationDate && ( )} + {oldValueData?.connectionExecutionDate && ( )} +
+ ); + }; + + var { connectionDetails, plumberDetails, roadCuttingDetails, activationDetails } = wsAdditionalDetails?.additionalDetails || {connectionDetails:[], plumberDetails: []}; + + // binding old values with new values + if(isModify === "MODIFY"){ + + connectionDetails = connectionDetails?.map((value) => { + if(value.title == "WS_SERV_DETAIL_CONN_TYPE" && oldValueData?.connectionType) value["oldValue"] = [ + { value:value?.value, className:"newValue", style:{ display:"inline"} }, + { + value:`${t("WS_OLD_LABEL_NAME")} ${oldValueData?.connectionType}`, + className:"oldValue", style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"} + }]; + if(value.title == "WS_SERV_DETAIL_NO_OF_TAPS" && oldValueData?.noOfTaps) value["oldValue"] = [ + {value:value?.value,className:"newValue", style:{ display:"inline"}}, + {value:`${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfTaps}`, style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"},className:"oldValue"} + ]; + if(value.title == "WS_SERV_DETAIL_WATER_SOURCE" && oldValueData?.waterSource) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${t(oldValueData?.waterSource?.toUpperCase()?.split(".")[0])}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_PIPE_SIZE_IN_INCHES_LABEL" && oldValueData?.pipeSize) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.pipeSize}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_SERV_DETAIL_WATER_SUB_SOURCE" && oldValueData?.waterSource) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${t(oldValueData?.waterSource?.toUpperCase()?.split(".")[1])}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_NUMBER_WATER_CLOSETS_LABEL" && oldValueData?.noOfWaterClosets) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfWaterClosets}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_SERV_DETAIL_NO_OF_TOILETS" && oldValueData?.noOfWaterClosets) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfWaterClosets}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + + return value; + }) + + plumberDetails = plumberDetails?.map((value) => { + if(value.title == "WS_ADDN_DETAILS_PLUMBER_PROVIDED_BY" && oldValueData?.additionalDetails?.detailsProvidedBy && oldValueData?.additionalDetails?.detailsProvidedBy !== value.value ) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.additionalDetails?.detailsProvidedBy}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_ADDN_DETAILS_PLUMBER_LICENCE_NO_LABEL" && oldValueData?.plumberInfo[0]?.licenseNo ) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.licenseNo}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_ADDN_DETAILS_PLUMBER_NAME_LABEL" && oldValueData?.plumberInfo[0]?.name ) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.name}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_PLUMBER_MOBILE_NO_LABEL" && oldValueData?.plumberInfo[0]?.mobileNumber ) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.mobileNumber}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + return value; + }) + + roadCuttingDetails = roadCuttingDetails?.map((roadDetail) => { + const roadDetailValues = roadDetail?.values?.map((value) => { + if(value.title == "WS_ADDN_DETAIL_ROAD_TYPE" && oldValueData?.roadCuttingInfo[0]?.roadType) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.roadCuttingInfo[0]?.roadType}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_ROAD_CUTTING_AREA_LABEL" && oldValueData?.roadCuttingInfo[0]?.roadCuttingArea) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.roadCuttingInfo[0]?.roadCuttingArea}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + return value; + }) + return ({...roadDetail,values:roadDetailValues}); + }) + + activationDetails = activationDetails?.map((value) => { + if(value.title == "WS_SERV_DETAIL_CONN_EXECUTION_DATE" && oldValueData?.connectionExecutionDate) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.connectionExecutionDate)}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + + if(value.title == "WS_SERV_DETAIL_METER_ID" && oldValueData?.meterId) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.meterId}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + + if(value.title == "WS_INITIAL_METER_READING_LABEL" && oldValueData?.initialMeterReading) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.initialMeterReading}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + + if(value.title == "WS_INSTALLATION_DATE_LABEL" && oldValueData?.meterInstallationDate) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.meterInstallationDate)}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_SERV_DETAIL_CONN_EXECUTION_DATE" && oldValueData?.connectionExecutionDate) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.connectionExecutionDate)}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + return value; + }) + }; + + return ( + +
+ {wsAdditionalDetails?.additionalDetails?.connectionDetails && ( + + {t("WS_COMMON_CONNECTION_DETAIL")} +
+
+ {connectionDetails?.map((value, index) => { + return ( +
+ +
+ ); + })} +
+
+
+ )} + {wsAdditionalDetails?.additionalDetails?.plumberDetails && ( + + {t("WS_COMMON_PLUMBER_DETAILS")} +
+
+ + {plumberDetails?.map((value, index) => { + return ; + })} +
+
+
+ )} + {wsAdditionalDetails?.additionalDetails?.roadCuttingDetails && ( + + {t("WS_ROAD_CUTTING_DETAILS")} +
+
+ {roadCuttingDetails?.map((value) => { + return ( +
1 + ? { + border: "1px solid #D6D5D4", + background: "#FAFAFA", + borderRadius: "4px", + padding: "10px 10px 0px 10px", + margin: "5px 0px", + } + : {} + } + > + {value?.values?.map((roadValue) => ( + + ))} +
+ ); + })} +
+
+
+ )} + {wsAdditionalDetails?.additionalDetails?.activationDetails && ( + + {t("WS_ACTIVATION_DETAILS")} +
+
+ {activationDetails?.map((value, index) => { + return ( + + ); + })} +
+
+
+ )} +
+
+ ); +}; + +export default WSAdditonalDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js new file mode 100644 index 00000000000..9a4fe591f9d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js @@ -0,0 +1,346 @@ +import React, { useState, Fragment, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { Card, CardSectionHeader, CardLabel } from "@egovernments/digit-ui-react-components"; +import { Modal, Dropdown, Row, StatusTable, TextInput, Toast } from "@egovernments/digit-ui-react-components"; +import cloneDeep from "lodash/cloneDeep"; + +const Penality_menu = [ + { + title: "PT_PENDING_DUES_FROM_EARLIER", + value: "Pending dues from earlier", + }, + { + title: "PT_MISCALCULATION_OF_EARLIER_ASSESSMENT", + value: "Miscalculation of earlier Assessment", + }, + { + title: "PT_ONE_TIME_PENALITY", + value: "One time penality", + }, + { + title: "PT_OTHERS", + value: "Others", + }, +] +const Rebate_menu = [ + { + title: "PT_ADVANCED_PAID_BY_CITIZEN_EARLIER", + value: "Advanced Paid By Citizen Earlier", + }, + { + title: "PT_REBATE_PROVIDED_BY_COMMISSIONER_EO", + value: "Rebate provided by commissioner/EO", + }, + { + title: "PT_ADDITIONAL_AMOUNT_CHARGED_FROM_THE_CITIZEN", + value: "Additional amount charged from the citizen", + }, + { + title: "PT_OTHERS", + value: "Others", + }, +]; + + +const WSFeeEstimation = ({ wsAdditionalDetails, workflowDetails }) => { + const { t } = useTranslation(); + const [sessionFormData, setSessionFormData, clearSessionFormData] = Digit.Hooks.useSessionStorage("ADHOC_ADD_REBATE_DATA", {}); + const [sessionBillFormData, setSessionBillFormData, clearBillSessionFormData] = Digit.Hooks.useSessionStorage("ADHOC_BILL_ADD_REBATE_DATA", {}); + const isPaid = wsAdditionalDetails?.additionalDetails?.isPaid ? true : false; + const [popup, showPopUp] = useState(false); + const [fields, setFields] = useState(sessionFormData ? sessionFormData : {}); + const [showToast, setShowToast] = useState(null); + const [billDetails, setBillDetails] = useState(wsAdditionalDetails.additionalDetails.data ? wsAdditionalDetails.additionalDetails.data : {}); + const [values, setValues] = useState(wsAdditionalDetails.additionalDetails.values ? wsAdditionalDetails.additionalDetails.values : []); + + const stateCode = Digit.ULBService.getStateId(); + const { isMdmsLoading, data: mdmsRes } = Digit.Hooks.ws.useMDMS(stateCode, "BillingService", ["TaxHeadMaster"]); + + useEffect(() => { + const data = { ...wsAdditionalDetails?.additionalDetails?.appDetails?.additionalDetails }; + setSessionFormData(data); + setFields(data); + if (sessionFormData?.billDetails?.length > 0) { + const values = [ + { title: "WS_APPLICATION_FEE_HEADER", value: sessionFormData?.billDetails?.[0]?.fee }, + { title: "WS_SERVICE_FEE_HEADER", value: sessionFormData?.billDetails?.[0]?.charge }, + { title: "WS_TAX_HEADER", value: sessionFormData?.billDetails?.[0]?.taxAmount }, + ]; + setValues(values); + setBillDetails(sessionFormData?.billDetails?.[0]); + } + }, []); + + let validation = {}; + + const Heading = (props) => { + return

{props.label}

; + }; + + const Close = () => ( + + + + + ); + + const CloseBtn = (props) => { + return ( +
+ +
+ ); + }; + + const closeToast = () => { + setShowToast(false); + }; + + const addAdhocRebatePenality = (e) => { + const adhocAmount = fields?.adhocPenalty ? Number(fields?.adhocPenalty) : 0; + const rebateAmount = fields?.adhocRebate ? Number(fields?.adhocRebate) : 0; + if (adhocAmount || rebateAmount) { + + const totalAmount = wsAdditionalDetails?.additionalDetails?.data?.totalAmount; + const demandId = wsAdditionalDetails?.additionalDetails?.data?.billDetails?.[0]?.demandId; + + if (rebateAmount > totalAmount) { + setShowToast({ isError: false, isWarning: true, key: "error", message: t("ERR_WS_REBATE_GREATER_THAN_AMOUNT") }); + } else { + const applicationNo = wsAdditionalDetails?.additionalDetails?.appDetails?.applicationNo; + const tenantId = wsAdditionalDetails?.additionalDetails?.appDetails?.tenantId; + const appAdditionalDetails = { ...wsAdditionalDetails?.additionalDetails?.appDetails?.additionalDetails, ...fields } + wsAdditionalDetails.additionalDetails.appDetails.additionalDetails = appAdditionalDetails; + + const data = { + CalculationCriteria: + wsAdditionalDetails?.additionalDetails?.appDetails?.service == "WATER" + ? [ + { + applicationNo: applicationNo, + tenantId: tenantId, + waterConnection: wsAdditionalDetails.additionalDetails.appDetails, + }, + ] + : [ + { + applicationNo: applicationNo, + tenantId: tenantId, + sewerageConnection: wsAdditionalDetails.additionalDetails.appDetails, + }, + ], + isconnectionCalculation: false, + }; + + let businessService = wsAdditionalDetails?.additionalDetails?.appDetails?.service == "WATER" ? "WS" : "SW"; + Digit.WSService.wsCalculationEstimate(data, businessService) + .then((result, err) => { + if (result?.Calculation?.[0]?.taxHeadEstimates?.length > 0) { + result?.Calculation?.[0]?.taxHeadEstimates?.forEach(data => data.amount = data.estimateAmount); + } + + result.Calculation[0].billSlabData = _.groupBy(result?.Calculation?.[0]?.taxHeadEstimates, 'category'); + const values = [ + { title: "WS_APPLICATION_FEE_HEADER", value: result.Calculation?.[0]?.fee }, + { title: "WS_SERVICE_FEE_HEADER", value: result.Calculation?.[0]?.charge }, + { title: "WS_TAX_HEADER", value: result.Calculation?.[0]?.taxAmount }, + ]; + setSessionBillFormData(cloneDeep(result.Calculation[0])); + setBillDetails(result?.Calculation?.[0]); + setValues(values); + fields.billDetails = result?.Calculation; + setSessionFormData(fields); + showPopUp(false); + }) + .catch((e) => { + setShowToast({ isError: true, isWarning: false, key: "error", message: e?.response?.data?.Errors[0]?.message ? t(`${e?.response?.data?.Errors[0]?.code}`) : t("PT_COMMON_ADD_REBATE_PENALITY") }); + }); + } + } else { + setShowToast({ isError: false, isWarning: true, key: "warning", message: t("ERR_WS_ENTER_ATLEAST_ONE_FIELD") }); + } + } + + const selectedValuesData = (value, isDropDownValue = false, e) => { + let values = { ...fields }; + if (isDropDownValue) { + values[`${value}_data`] = e; + values[value] = e.title; + if (e.title == "PT_OTHERS" && value == "adhocPenaltyReason") values[`adhocPenaltyComment`] = ""; + if (e.title == "PT_OTHERS" && value == "adhocRebateReason") values[`adhocRebateComment`] = ""; + } else { + values[value] = e.target.value; + } + setFields(values); + } + + return ( + +
+ {values && + +
+ {values?.map((value, index) => { + return + })} +
+
+
+ + +
+
} + { + wsAdditionalDetails?.additionalDetails?.isAdhocRebate ?
{ + showPopUp(true) + }} + > + {t("WS_PAYMENT_ADD_REBATE_PENALTY")} +
: null + } + {popup && + } + headerBarEnd={ + { + setFields(sessionFormData); + showPopUp(false); + }} />} + actionCancelLabel={t("PT_CANCEL")} + actionCancelOnSubmit={() => { + setFields(sessionFormData); + showPopUp(false); + }} + actionSaveLabel={t("PT_ADD")} + actionSaveOnSubmit={(e) => addAdhocRebatePenality(e)} + hideSubmit={false} + popupStyles={{ overflowY: "auto" }} + > + { +
+ + {t("PT_AD_PENALTY")} + + {t("PT_TX_HEADS")} + +
+ selectedValuesData("adhocPenaltyReason", true, e)} + selected={fields?.adhocPenaltyReason_data || ""} + isPropertyAssess={true} + name={"adhocPenaltyReason_data"} + t={t} + /> +
+ {fields?.adhocPenaltyReason_data?.title === "PT_OTHERS" &&
+ {t("PT_REASON")} +
+ selectedValuesData("adhocPenaltyComment", false, e)} + {...(validation = { + isRequired: true, + pattern: "^[a-zA-Z-.`' ]*$", + type: "text", + title: t("TL_NAME_ERROR_MESSAGE"), + })} + /> +
+
} + {t("PT_HEAD_AMT")} +
+ selectedValuesData("adhocPenalty", false, e)} + {...(validation = { + isRequired: true, + pattern: "^[1-9]+[0-9]*$", + title: t("ERR_DEFAULT_INPUT_FIELD_MSG"), + })} + /> + +
+
+ + {t("PT_AD_REBATE")} + {t("PT_TX_HEADS")} +
+ selectedValuesData("adhocRebateReason", true, e)} + selected={fields?.adhocRebateReason_data || ""} + name={"adhocRebateReason_data"} + isPropertyAssess={true} + t={t} + /> +
+ {fields?.adhocRebateReason_data?.title === "PT_OTHERS" &&
+ {t("PT_REASON")} + selectedValuesData("adhocRebateComment", false, e)} + {...(validation = { + isRequired: true, + pattern: "^[a-zA-Z-.`' ]*$", + type: "text", + title: t("TL_NAME_ERROR_MESSAGE"), + })} + /> +
} + {t("PT_HEAD_AMT")} +
+ selectedValuesData("adhocRebate", false, e)} + {...(validation = { + isRequired: true, + pattern: "^[1-9]+[0-9]*$", + title: t("ERR_DEFAULT_INPUT_FIELD_MSG"), + })} + /> +
+
+
+ }
} + {showToast && + } +
+
+ ) +} + +export default WSFeeEstimation; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js new file mode 100644 index 00000000000..75069dd741f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js @@ -0,0 +1,30 @@ +import React, { useCallback, useState } from "react"; +import { useTranslation } from "react-i18next"; + +const WeekDateRange = (props) => { + const [localSearchParams, setLocalSearchParams] = useState(() => ({})); + const { t } = useTranslation(); + const handleChange = useCallback((data) => { + setLocalSearchParams(() => ({ ...data })); + }, []); + + return ( +
+
+

{props.title}

+
+ +
+
+
+ ); +}; + +export default WeekDateRange; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js new file mode 100644 index 00000000000..e870f2e9a67 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js @@ -0,0 +1,45 @@ +import React from "react"; +import { Dropdown } from "@egovernments/digit-ui-react-components"; + +export const configAcceptDso = ({ t, dsoData, dso, selectVehicleNo, vehicleNoList, vehicleNo, vehicle, action }) => { + return { + label: { + heading: `ES_FSM_ACTION_TITLE_${action}`, + submit: `CS_COMMON_${action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("ES_FSM_ACTION_VEHICLE_REGISTRATION_NO"), + isMandatory: true, + type: "dropdown", + populators: ( + + ), + }, + { + label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), + isMandatory: true, + type: "text", + populators: { + name: "capacity", + validation: { + required: true, + }, + }, + disable: true, + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js new file mode 100644 index 00000000000..418caf1e4bc --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js @@ -0,0 +1,115 @@ +import React from "react"; +import { DatePicker, Dropdown, CardLabelError } from "@egovernments/digit-ui-react-components"; + +function todayDate() { + var today = new Date(); + var dd = today.getDate(); + var mm = today.getMonth() + 1; + var yyyy = today.getFullYear(); + + if (dd < 10) { + dd = "0" + dd; + } + + if (mm < 10) { + mm = "0" + mm; + } + + return yyyy + "-" + mm + "-" + dd; +} + +function getFilteredDsoData(dsoData, vehicle) { + return dsoData?.filter((e) => e.vehicles?.find((veh) => veh?.type == vehicle?.code)); +} + +export const configAssignDso = ({ t, dsoData, dso, selectDSO, vehicleMenu, vehicle, selectVehicle, action }) => { + return { + label: { + heading: `ES_FSM_ACTION_TITLE_${action}`, + submit: `CS_COMMON_${action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("ES_FSM_ACTION_VEHICLE_TYPE"), + isMandatory: true, + type: "dropdown", + populators: ( + + ), + }, + { + label: t("ES_FSM_ACTION_DSO_NAME"), + isMandatory: true, + type: "dropdown", + populators: ( + + {getFilteredDsoData(dsoData, vehicle) && !getFilteredDsoData(dsoData, vehicle).length ? ( + {t("ES_COMMON_NO_DSO_AVAILABLE_WITH_SUCH_VEHICLE")} + ) : null} + + + ), + }, + { + label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), + isMandatory: true, + type: "text", + populators: { + name: "capacity", + validation: { + required: true, + }, + }, + disable: true, + }, + // { + // label: t("ES_FSM_ACTION_SERVICE_DATE"), + // isMandatory: true, + // type: "date", + // populators: { + // name: "date", + // validation: { + // required: true, + // }, + // min: Digit.Utils.date.getDate(), + // defaultValue: Digit.Utils.date.getDate(), + // }, + // }, + { + label: t("ES_FSM_ACTION_SERVICE_DATE"), + isMandatory: true, + type: "custom", + populators: { + name: "date", + validation: { + required: true, + }, + customProps: { min: Digit.Utils.date.getDate() }, + defaultValue: Digit.Utils.date.getDate(), + component: (props, customProps) => , + }, + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js new file mode 100644 index 00000000000..ca66865bb77 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js @@ -0,0 +1,77 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configBPAApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, + error +}) => { + let isRejectOrRevocate = false; + if(action?.action == "REVOCATE" || action?.action == "REJECT" || action.action == "SKIP_PAYMENT" || action?.action == "SEND_BACK_TO_CITIZEN" || action?.action == "APPROVE") { + isRejectOrRevocate = true; + } + + let isCommentRequired = false; + if(action?.action == "REVOCATE" || action?.action == "REJECT") { + isCommentRequired = true; + } + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService}_${action?.action}`, + cancel: "BPA_CITIZEN_CANCEL_BUTTON", + }, + form: [ + { + body: [ + { + label: action.isTerminateState || isRejectOrRevocate ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), + type: "dropdown", + populators: action.isTerminateState || isRejectOrRevocate ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + isMandatory: isCommentRequired, + populators: { + name: "comments", + }, + }, + { + label: `${t("WF_APPROVAL_UPLOAD_HEAD")}`, + populators: ( + { + setUploadedFile(null); + }} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + accept= "image/*, .pdf, .png, .jpeg, .jpg" + iserror={error} + /> + ), + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js new file mode 100644 index 00000000000..0bdba14bc5b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js @@ -0,0 +1,71 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configBPAREGApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, + error +}) => { + let checkCondtions = true; + if (action?.action == "SENDBACKTOCITIZEN") checkCondtions = false; + if (action.isTerminateState) checkCondtions = false; + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, + cancel: "WF_EMPLOYEE_BPAREG_CANCEL", + }, + form: [ + { + body: [ + { + label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), + placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + type: "dropdown", + populators: !checkCondtions ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + { + label: t("BPA_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), + populators: ( + { + setUploadedFile(null); + }} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + accept= "image/*, .pdf, .png, .jpeg, .jpg" + iserror={error} + /> + ) + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js new file mode 100644 index 00000000000..a4c7c96b2fd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js @@ -0,0 +1,46 @@ +import React from "react"; +import { DatePicker } from "@egovernments/digit-ui-react-components"; + +export const configCompleteApplication = ({ t, vehicle, applicationCreatedTime = 0, action }) => ({ + label: { + heading: `ES_FSM_ACTION_TITLE_${action}`, + submit: `CS_COMMON_${action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("ES_FSM_ACTION_DESLUGED_DATE_LABEL"), + isMandatory: true, + type: "custom", + populators: { + name: "desluged", + validation: { + required: true, + }, + defaultValue: Digit.Utils.date.getDate(), + customProps: { + min: Digit.Utils.date.getDate(applicationCreatedTime), + max: Digit.Utils.date.getDate(), + }, + component: (props, customProps) => , + }, + }, + { + label: t("ES_FSM_ACTION_WASTE_VOLUME_LABEL"), + type: "text", + isMandatory: true, + populators: { + name: "wasteCollected", + validation: { + required: true, + validate: (value) => parseInt(value) <= parseInt(vehicle.capacity), + }, + error: `${t("ES_FSM_ACTION_INVALID_WASTE_VOLUME")} ${vehicle?.capacity} ${t("CS_COMMON_LITRES")}`, + }, + }, + ], + }, + ], +}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js new file mode 100644 index 00000000000..12922b0575e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js @@ -0,0 +1,79 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configNOCApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, + error +}) => { + + let isCommentRequired = false; + if(action?.action == "REVOCATE" || action?.action == "REJECT") { + isCommentRequired = true; + } + + let isRejectOrRevocate = false; + if(action?.action == "APPROVE" || action?.action == "REJECT" || action.action == "AUTO_APPROVE" || action.action == "AUTO_REJECT") { + isRejectOrRevocate = true; + } + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService}_${action?.action}`, + cancel: "CORE_LOGOUTPOPUP_CANCEL", + }, + form: [ + { + body: [ + { + label: action.isTerminateState || isRejectOrRevocate ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), + type: "dropdown", + populators: action.isTerminateState || isRejectOrRevocate ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + isMandatory: isCommentRequired, + populators: { + name: "comments", + }, + }, + { + label: `${t("WF_APPROVAL_UPLOAD_HEAD")}`, + populators: ( + { + setUploadedFile(null); + }} + showHint={true} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + accept= "image/*, .pdf, .png, .jpeg, .jpg" + iserror={error} + /> + ), + }, + ], + }, + ], + }; +}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js new file mode 100644 index 00000000000..afcc6a19be2 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js @@ -0,0 +1,66 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configPTApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, +}) => { + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService}_${action?.action}`, + cancel: "ES_PT_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: action.isTerminateState || action?.action === "SENDBACKTOCITIZEN" ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), + // isMandatory: !action.isTerminateState, + type: "dropdown", + populators: action.isTerminateState || action?.action === "SENDBACKTOCITIZEN" ? null : ( + + ), + }, + { + label: t("ES_PT_ACTION_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + { + label: `${t("ES_PT_ATTACH_FILE")}${action.docUploadRequired ? " *" : ""}`, + populators: ( + { + setUploadedFile(null); + }} + showHint={true} + hintText={t("PT_ATTACH_RESTRICTIONS_SIZE")} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`ES_PT_ACTION_NO_FILEUPLOADED`)} + /> + ), + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js new file mode 100644 index 00000000000..dd04037aab6 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js @@ -0,0 +1,26 @@ +import React from "react"; +import { RadioButtons } from "@egovernments/digit-ui-react-components"; + +export const configPTAssessProperty = ({ t, action, financialYears, selectedFinancialYear, setSelectedFinancialYear }) => { + return { + label: { + heading: `WF_${action.action}_APPLICATION`, + submit: `WF_PT.CREATE_${action.action}`, + cancel: "ES_PT_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("ES_PT_FINANCIAL_YEARS"), + isMandatory: true, + type: "radio", + populators: ( + + ), + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js new file mode 100644 index 00000000000..132a5bc6a7c --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js @@ -0,0 +1,101 @@ +import React from "react"; +import { Dropdown } from "@egovernments/digit-ui-react-components"; + +function getFilteredDsoData(dsoData, vehicle) { + return dsoData?.filter((e) => e.vehicles?.find((veh) => veh?.type == vehicle?.code)); +} + +export const configReassignDSO = ({ + t, + dsoData, + dso, + selectDSO, + vehicleMenu, + vehicle, + selectVehicle, + reassignReasonMenu, + reassignReason, + selectReassignReason, + action, + showReassignReason, +}) => ({ + label: { + heading: `ES_FSM_ACTION_TITLE_${action}`, + submit: `CS_COMMON_${action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + ...(showReassignReason + ? [ + { + label: t("ES_FSM_ACTION_REASSIGN_REASON"), + type: "dropdown", + isMandatory: true, + populators: ( + + ), + }, + ] + : []), + { + label: t("ES_FSM_ACTION_VEHICLE_TYPE"), + isMandatory: vehicle ? false : true, + type: "dropdown", + populators: ( + + ), + }, + { + label: t("ES_FSM_ACTION_DSO_NAME"), + isMandatory: true, + type: "dropdown", + populators: ( + + ), + }, + { + label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), + type: "text", + populators: { + name: "capacity", + validation: { + required: true, + }, + }, + disable: true, + }, + { + label: t("ES_FSM_ACTION_SERVICE_DATE"), + isMandatory: true, + type: "date", + populators: { + name: "date", + validation: { + required: true, + }, + min: Digit.Utils.date.getDate(), + defaultValue: Digit.Utils.date.getDate(), + }, + }, + ], + }, + ], +}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js new file mode 100644 index 00000000000..a18bdaf1110 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js @@ -0,0 +1,31 @@ +import React from "react"; +import { Dropdown } from "@egovernments/digit-ui-react-components"; + +export const configRejectApplication = ({ t, rejectMenu, setReason, reason, action }) => { + return { + label: { + heading: `ES_FSM_ACTION_TITLE_${action}`, + submit: `CS_COMMON_${action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t(`ES_FSM_ACTION_${action.toUpperCase()}_REASON`), + type: "dropdown", + populators: , + isMandatory: true, + }, + { + label: t("ES_FSM_ACTION_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js new file mode 100644 index 00000000000..23b20e5be2b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js @@ -0,0 +1,83 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configTLApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, +}) => { + let checkCondtions = true; + if (action?.action == "SENDBACKTOCITIZEN" || action?.action == "APPROVE") checkCondtions = false; + if (action.isTerminateState) checkCondtions = false; + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, + cancel: "WF_EMPLOYEE_NEWTL_CANCEL", + }, + form: [ + { + body: [ + { + label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), + placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + // isMandatory: false, + type: "dropdown", + populators: !checkCondtions ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + { + label: t("TL_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), + populators: ( + { + setUploadedFile(null); + }} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + /> + ) + }, + // { + // label: action.docUploadRequired ? t("ES_PT_UPLOAD_FILE") : null, + // populators: action.docUploadRequired ? ( + // { + // setUploadedFile(null); + // }} + // message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`ES_PT_ACTION_NO_FILEUPLOADED`)} + // /> + // ) : null, + // }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js new file mode 100644 index 00000000000..2f5f2d45a6a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js @@ -0,0 +1,73 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configWSApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, + error +}) => { + let checkCondtions = true; + if (action?.action?.includes("SEND_BACK") || action?.action == "APPROVE_FOR_CONNECTION") checkCondtions = false; + if (action.isTerminateState) checkCondtions = false; + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), + placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + // isMandatory: false, + type: "dropdown", + populators: !checkCondtions ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + { + label: t("WS_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), + populators: ( + { + setUploadedFile(null); + }} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + error={error} + iserror={error} + /> + ) + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js new file mode 100644 index 00000000000..5acdcebe041 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js @@ -0,0 +1,89 @@ +import { Dropdown, UploadFile, DatePicker } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configWSDisConnectApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, + error +}) => { + let checkCondtions = true, isDatePickerDisplay = false; + if (action?.action?.includes("SEND_BACK") || action?.action == "APPROVE_FOR_DISCONNECTION" || action?.action == "RESUBMIT_APPLICATION") checkCondtions = false; + if (action.isTerminateState) checkCondtions = false; + if (action?.action == "EXECUTE_DISCONNECTION" || action?.action == "DISCONNECTION_EXECUTED") isDatePickerDisplay = true; + + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), + placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + // isMandatory: false, + type: "dropdown", + populators: !checkCondtions ? null : ( + + ), + }, + isDatePickerDisplay && { + label: t("ES_FSM_ACTION_SERVICE_DATE"), + isMandatory: isDatePickerDisplay ? true : false, + type: "custom", + populators: isDatePickerDisplay ? { + name: "date", + validation: { + required: true, + }, + // customProps: { max: Digit.Utils.date.getDate() }, + defaultValue: Digit.Utils.date.getDate(), + component: (props, customProps) => , + } : null, + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + { + label: t("WS_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), + populators: ( + { + setUploadedFile(null); + }} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + error={error} + iserror={error} + /> + ) + }, + ], + }, + ], + }; +}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js new file mode 100644 index 00000000000..03beb885925 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js @@ -0,0 +1,53 @@ +import { Dropdown } from '@egovernments/digit-ui-react-components'; +import React, { useState } from 'react' + +const configApproveModal = ({ + t, + action +}) => { + if(action?.action === 'ADMINSANCTION'){ + return { + label: { + heading: `WORKS_APPROVE_ESTIMATE`, + submit: `WORKS_APPROVE_ESTIMATE`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } + + }else + return { + label: { + heading: `WORKS_APPROVE_LOI`, + submit: `WORKS_APPROVE_LOI`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } +} + +export default configApproveModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js new file mode 100644 index 00000000000..06a29a26339 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js @@ -0,0 +1,27 @@ + +const configAttendanceApproveModal = ({ t, action }) => { + if (action?.applicationStatus === "APPROVED") { + return { + label: { + heading: t("ATM_PROCESSINGMODAL_HEADER"), + submit: t("ATM_FORWARD_FOR_APPROVAL"), + cancel: t("CS_COMMON_CANCEL"), + }, + form: [ + { + body: [ + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ], + }, + ] + }; + } +}; + +export default configAttendanceApproveModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js new file mode 100644 index 00000000000..374219cc6d4 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js @@ -0,0 +1,93 @@ +const configAttendanceCheckModal = ({ + t, + action, + businessService, + approvers, + selectedApprover, + setSelectedApprover, + designation, + selectedDesignation, + setSelectedDesignation, + department, + selectedDept, + setSelectedDept, + approverLoading = false, +}) => { + let checkConditions = true; + if (action.isTerminateState) checkConditions = false; + + if (designation?.length === 0 || department?.length === 0) return {}; + + if (action?.applicationStatus === "ATTENDANCE_CHECKED") { + return { + label: { + heading: t("ATM_PROCESSINGMODAL_HEADER"), + submit: t("ATM_FORWARD_FOR_CHECK"), + cancel: t("WORKS_CANCEL"), + }, + form: [ + { + body: [ + { + isMandatory: true, + key: "department", + type: "radioordropdown", + label: !checkConditions ? null : t("ATM_APPROVER_DEPT"), + disable: false, + populators: { + name: "department", + optionsKey: "i18nKey", + error: "Department is required", + required: true, + options: department, + }, + }, + { + isMandatory: true, + key: "designation", + type: "radioordropdown", + label: !checkConditions ? null : t("ATM_APPROVER_DESIGNATION"), + disable: false, + populators: { + name: "designation", + optionsKey: "i18nKey", + error: "Designation is required", + required: true, + options: designation, + }, + }, + { + isMandatory: true, + key: "approvers", + type: "radioordropdown", + label: !checkConditions ? null : t("WORKS_APPROVER"), + disable: false, + populators: { + name: "approvers", + optionsKey: "nameOfEmp", + error: "Designation is required", + required: true, + options: approvers, + }, + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ], + }, + ], + defaultValues: { + department: "", + designation: "", + approvers: "", + comments: "", + }, + }; + } +}; + +export default configAttendanceCheckModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js new file mode 100644 index 00000000000..c732127aac7 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js @@ -0,0 +1,61 @@ +import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; +import React from 'react' + +const configAttendanceRejectModal = ({ + t, + empDepartment, + empDesignation, + empName +}) => { + + const fieldLabelStyle = { + "display" : "grid", + "gridTemplateColumns" : "60% 1fr" + }; + + return { + label: { + heading: t("ATM_PROCESSINGMODAL_HEADER"), + submit: t("ATM_CONFIRM_REJECT"), + cancel: t("CS_COMMON_CANCEL"), + }, + form: [ + { + body: [ + { + withoutLabel:true, + populators: + {t("ATM_DEPARTMENT")} + {empDepartment} + , + }, + { + withoutLabel:true, + populators: + {t("ATM_DESIGNATION")} + {empDesignation} + , + }, + { + withoutLabel:true, + populators: + {t("ATM_REJECTED_BY")} + {empName} + , + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + key: "org_name", + populators: { + name: "comments", + }, + }, + ] + } + ] + } + +} + +export default configAttendanceRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js new file mode 100644 index 00000000000..c267eb9f32f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js @@ -0,0 +1,105 @@ +import { Dropdown,Loader } from '@egovernments/digit-ui-react-components'; +import React,{useState} from 'react' + +const configCheckModal = ({ + t, + action, + businessService, + approvers, + selectedApprover, + setSelectedApprover, + designation, + selectedDesignation, + setSelectedDesignation, + department, + selectedDept, + setSelectedDept, + approverLoading=false, +}) => { + + let checkConditions = true + if (action.isTerminateState) checkConditions = false; + + if(designation?.length===0 || department?.length===0) return {} + + return { + label: { + heading: `WORKS_CHECK_FORWARD`, + submit: `WORKS_FORWARD_FOR_APPROVAL`, + cancel: "WORKS_CANCEL", + }, + form: [ + { + body:[ + { + label: !checkConditions ? null : t("WORKS_APPROVER_DEPT"), + placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + { + setSelectedDept(val) + setSelectedApprover("") + //setValue() + }} + selected={selectedDept} + t={t} + /> + ), + }, + { + label: !checkConditions ? null : t("WORKS_APPROVER_DESIGNATION"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + { + setSelectedDesignation(val) + setSelectedApprover("") + //resetting approver dropdown when dept/designation changes + }} + selected={selectedDesignation} + t={t} + /> + ), + }, + { + label: !checkConditions ? null : t("WORKS_APPROVER"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + approverLoading ? : + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } +} + +export default configCheckModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js new file mode 100644 index 00000000000..ae4be5af3fd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js @@ -0,0 +1,127 @@ +import { Dropdown,LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; +import React, { useState } from 'react' + +const configRejectModal = ({ + t, + action, + rejectReasons, + selectedReason, + setSelectedReason, + loiNumber, + department, + estimateNumber +}) => { + + let checkConditions = true + if (action.isTerminateState) checkConditions = false; + + if(rejectReasons?.length === 0) return {} + if(loiNumber){ + return { + label: { + heading: `WORKS_REJECT_LOI`, + submit: `WORKS_REJECT_LOI`, + //cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + withoutLabel:true, + populators: + {t("WORKS_DEPARTMENT")} + {"ENGG"} + , + }, + { + //label: t("WORKS_LOI_ID"), + //type: "text", + withoutLabel: true, + populators: + {t("WORKS_LOI_ID")} + {loiNumber} + + }, + { + label: !checkConditions ? null : t("WORKS_REJECT_REASON"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + // isMandatory: false, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } + }else{ + return { + label: { + heading: `WORKS_REJECT_ESTIMATE`, + submit: `WORKS_REJECT_ESTIMATE`, + //cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + withoutLabel:true, + populators: + {t("WORKS_DEPARTMENT")} + {"ENGG"} + , + }, + { + //label: t("WORKS_LOI_ID"), + //type: "text", + withoutLabel: true, + populators: + {t("WORKS_ESTIMATE_ID")} + {estimateNumber} + + }, + { + label: !checkConditions ? null : t("WORKS_REJECT_REASON"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + // isMandatory: false, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } + + } +} + +export default configRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js new file mode 100644 index 00000000000..cd01fdc4414 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js @@ -0,0 +1,57 @@ +import React from 'react' +import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; + +const configViewBillApprovalModal = ({ + t, +}) => { + const fieldLabelStyle = { + "display" : "grid", + "gridTemplateColumns" : "60% 1fr" + }; + return { + label: { + heading: t("EXP_PROCESSINGMODAL_HEADER"), + submit: t("EXP_FORWARD_FOR_APPROVAL"), + cancel: t("CS_COMMON_CANCEL"), + }, + form: [ + { + body: [ + { + withoutLabel:true, + populators: + {t("EXP_DEPARTMENT")} + Engineering + , + }, + { + withoutLabel:true, + populators: + {t("EXP_DESIGNATION")} + Junior Engineer + , + }, + { + withoutLabel:true, + populators: + {t("EXP_APPROVER")} + {"RASHMI"} + , + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ], + }, + ], + defaultValues: { + comments: "", + }, + }; +} + +export default configViewBillApprovalModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js new file mode 100644 index 00000000000..53204b28e75 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js @@ -0,0 +1,107 @@ +import { Dropdown, Loader } from '@egovernments/digit-ui-react-components'; +import React, { useState } from 'react' + +const configViewBillCheckModal = ({ + t, + approvers, + selectedApprover, + setSelectedApprover, + designation, + selectedDesignation, + setSelectedDesignation, + department, + selectedDept, + setSelectedDept, + approverLoading = false, +}) => { + + let checkConditions = true + + + if (designation?.length === 0 || department?.length === 0) return {} + + return { + label: { + heading: t("EXP_FORWARD_BILL_FOR_APPROVAL"), + submit: t("EXP_FORWARD_BILL_FOR_APPROVAL"), + cancel: t("CS_COMMON_CANCEL"), + }, + form: [ + { + body: [ + { + label: !checkConditions ? null : t("WORKS_APPROVER_DEPT"), + placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + { + setSelectedDept(val) + setSelectedApprover("") + //setValue() + }} + selected={selectedDept} + t={t} + /> + ), + }, + { + label: !checkConditions ? null : t("WORKS_APPROVER_DESIGNATION"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + name: "designation", + populators: !checkConditions ? null : ( + { + setSelectedDesignation(val) + setSelectedApprover("") + //resetting approver dropdown when dept/designation changes + }} + selected={selectedDesignation} + t={t} + /> + ), + }, + { + label: !checkConditions ? null : t("WORKS_APPROVER"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + approverLoading ? : + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } +} + +export default configViewBillCheckModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js new file mode 100644 index 00000000000..716d6179d10 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js @@ -0,0 +1,59 @@ +import React from 'react' +import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; + +const configViewBillRejectModal = ({ + t, +}) => { + + const fieldLabelStyle = { + "display" : "grid", + "gridTemplateColumns" : "60% 1fr" + }; + + return { + label: { + heading: t("EXP_PROCESSINGMODAL_HEADER"), + submit: t("EXP_CONFIRM_REJECT"), + cancel: t("CS_COMMON_CANCEL"), + }, + form: [ + { + body: [ + { + withoutLabel:true, + populators: + {t("EXP_DEPARTMENT")} + Engineering + , + }, + { + withoutLabel:true, + populators: + {t("EXP_DESIGNATION")} + Junior Engineer + , + }, + { + withoutLabel:true, + populators: + {t("EXP_REJECTED_BY")} + {"RASHMI"} + , + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ], + defaultValues : { + comments : "", + } + } +} + +export default configViewBillRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js new file mode 100644 index 00000000000..a736b8ed3eb --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js @@ -0,0 +1,47 @@ +import { configAssignDso } from "./AssignDso"; +import { configCompleteApplication } from "./CompleteApplication"; +import { configReassignDSO } from "./ReassignDso"; +import { configRejectApplication } from "./RejectApplication"; +import { configAcceptDso } from "./AcceptDso"; +import { configPTApproverApplication } from "./PTApproverApplication"; +import { configPTAssessProperty } from "./PTAssessProperty"; +import { configTLApproverApplication } from "./TLApproverApplication"; +import { configBPAREGApproverApplication } from "./BPAREGApproverApplication"; +import { configBPAApproverApplication } from "./BPAApproverApplication"; +import { configNOCApproverApplication } from "./NOCApproverApplication"; +import { configWSApproverApplication } from "./WSApproverApplication"; +import { configWSDisConnectApplication } from "./WSDisconnectApplication"; +import configCheckModal from "./configCheckModal" +import configApproveModal from "./configApproveModal" +import configRejectModal from "./configRejectModal" +import configAttendanceApproveModal from "./configAttendanceApproveModal"; +import configAttendanceCheckModal from "./configAttendanceCheckModal"; +import configAttendanceRejectModal from "./configAttendanceRejectModal"; +import configViewBillApproveModal from "./configViewBillApproveModal"; +import configViewBillCheckModal from "./configViewBillCheckModal"; +import configViewBillRejectModal from "./configViewBillRejectModal"; + +export { + configAttendanceRejectModal, + configAttendanceCheckModal, + configAttendanceApproveModal, + configCheckModal, + configApproveModal, + configRejectModal, + configAssignDso, + configCompleteApplication, + configReassignDSO, + configRejectApplication, + configAcceptDso, + configPTApproverApplication, + configPTAssessProperty, + configTLApproverApplication, + configBPAREGApproverApplication, + configBPAApproverApplication, + configNOCApproverApplication, + configWSApproverApplication, + configWSDisConnectApplication, + configViewBillRejectModal, + configViewBillCheckModal, + configViewBillApproveModal +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js new file mode 100644 index 00000000000..feb622ab712 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js @@ -0,0 +1,368 @@ +import React, { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useQueryClient } from "react-query"; +import { format } from "date-fns"; + +import { Loader } from "@egovernments/digit-ui-react-components"; + +import ActionModal from "./Modal"; + +import { useHistory, useParams } from "react-router-dom"; +import ApplicationDetailsContent from "./components/ApplicationDetailsContent"; +import ApplicationDetailsToast from "./components/ApplicationDetailsToast"; +import ApplicationDetailsActionBar from "./components/ApplicationDetailsActionBar"; +import ApplicationDetailsWarningPopup from "./components/ApplicationDetailsWarningPopup"; + +const ApplicationDetails = (props) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + const state = Digit.ULBService.getStateId(); + const { t } = useTranslation(); + const history = useHistory(); + let { id: applicationNumber } = useParams(); + const [displayMenu, setDisplayMenu] = useState(false); + const [selectedAction, setSelectedAction] = useState(null); + const [showModal, setShowModal] = useState(false); + const [isEnableLoader, setIsEnableLoader] = useState(false); + const [isWarningPop, setWarningPopUp] = useState(false); + const [modify, setModify] = useState(false); + const [saveAttendanceState, setSaveAttendanceState] = useState({ displaySave : false, updatePayload: []}) + + const { + applicationDetails, + showToast, + setShowToast, + isLoading, + isDataLoading, + applicationData, + mutate, + nocMutation, + workflowDetails, + businessService, + closeToast, + moduleCode, + timelineStatusPrefix, + forcedActionPrefix, + statusAttribute, + ActionBarStyle, + MenuStyle, + paymentsList, + showTimeLine = true, + oldValue, + isInfoLabel = false, + clearDataDetails, + noBoxShadow, + sectionHeadStyle, + showActionBar = true + } = props; + + useEffect(() => { + if (showToast) { + workflowDetails.revalidate(); + } + }, [showToast]); + + function onActionSelect(action) { + if (action) { + if(action?.isToast){ + setShowToast({ key: "error", error: { message: action?.toastMessage } }); + setTimeout(closeToast, 5000); + } + else if (action?.isWarningPopUp) { + setWarningPopUp(true); + } else if (action?.redirectionUrll) { + //here do the loi edit upon rejection + if (action?.redirectionUrll?.action === "EDIT_LOI_APPLICATION") { + history.push(`${action?.redirectionUrll?.pathname}`, { data: action?.redirectionUrll?.state }); + } + if (action?.redirectionUrll?.action === "EDIT_ESTIMATE_APPLICATION") { + history.push(`${action?.redirectionUrll?.pathname}`,{ data: action?.redirectionUrll?.state }); + } + + } else if (!action?.redirectionUrl) { + if(action?.action === 'EDIT') setModify(true) + else setShowModal(true); + } else { + history.push({ + pathname: action.redirectionUrl?.pathname, + state: { ...action.redirectionUrl?.state }, + }); + } + } + setSelectedAction(action); + setDisplayMenu(false); + } + + const queryClient = useQueryClient(); + + const closeModal = () => { + setSelectedAction(null); + setShowModal(false); + }; + + const closeWarningPopup = () => { + setWarningPopUp(false); + }; + + const getResponseHeader = (action) => { + + if(action?.includes("CHECK")){ + return t("WORKS_LOI_RESPONSE_FORWARD_HEADER") + } else if (action?.includes("APPROVE")){ + return t("WORKS_LOI_RESPONSE_APPROVE_HEADER") + }else if(action?.includes("REJECT")){ + return t("WORKS_LOI_RESPONSE_REJECT_HEADER") + } + } + + const getResponseMessage = (action,updatedLOI) => { + + if (action?.includes("CHECK")) { + return t("WORKS_LOI_RESPONSE_MESSAGE_CHECK", { loiNumber: updatedLOI?.letterOfIndentNumber,name:"Nipun",designation:"SE" }) + } else if (action?.includes("APPROVE")) { + return t("WORKS_LOI_RESPONSE_MESSAGE_APPROVE", { loiNumber: updatedLOI?.letterOfIndentNumber }) + } else if (action?.includes("REJECT")) { + return t("WORKS_LOI_RESPONSE_MESSAGE_REJECT", { loiNumber: updatedLOI?.letterOfIndentNumber }) + } + } + + const getEstimateResponseHeader = (action) => { + + if(action?.includes("CHECK")){ + return t("WORKS_ESTIMATE_RESPONSE_FORWARD_HEADER") + } else if (action?.includes("TECHNICALSANCATION")){ + return t("WORKS_ESTIMATE_RESPONSE_FORWARD_HEADER") + }else if (action?.includes("ADMINSANCTION")){ + return t("WORKS_ESTIMATE_RESPONSE_APPROVE_HEADER") + }else if(action?.includes("REJECT")){ + return t("WORKS_ESTIMATE_RESPONSE_REJECT_HEADER") + } + } + + const getEstimateResponseMessage = (action,updatedEstimate) => { + + if (action?.includes("CHECK")) { + return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_CHECK", { estimateNumber: updatedEstimate?.estimateNumber,Name:"Super",Designation:"SE",Department:"Health" }) + } else if (action?.includes("TECHNICALSANCATION")) { + return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_CHECK", { estimateNumber: updatedEstimate?.estimateNumber,Name:"Super",Designation:"SE",Department:"Health" }) + } else if (action?.includes("ADMINSANCTION")) { + return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_APPROVE", { estimateNumber: updatedEstimate?.estimateNumber }) + } else if (action?.includes("REJECT")) { + return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_REJECT", { estimateNumber: updatedEstimate?.estimateNumber }) + } + } + + const getAttendanceResponseHeaderAndMessage = (action) => { + let response = {} + if (action?.includes("VERIFY")) { + response.header = t("ATM_ATTENDANCE_VERIFIED") + response.message = t("ATM_ATTENDANCE_VERIFIED_SUCCESS") + } else if (action?.includes("REJECT")) { + response.header = t("ATM_ATTENDANCE_REJECTED") + response.message = t("ATM_ATTENDANCE_REJECTED_SUCCESS") + } else if (action?.includes("APPROVE")) { + response.header = t("ATM_ATTENDANCE_APPROVED") + response.message = t("ATM_ATTENDANCE_APPROVED_SUCCESS") + } + return response + } + + const submitAction = async (data, nocData = false, isOBPS = {}) => { + const performedAction = data?.workflow?.action + setIsEnableLoader(true); + if (mutate) { + setIsEnableLoader(true); + mutate(data, { + onError: (error, variables) => { + setIsEnableLoader(false); + setShowToast({ key: "error", error }); + setTimeout(closeToast, 5000); + }, + onSuccess: (data, variables) => { + setIsEnableLoader(false); + //just history.push to the response component from here and show relevant details + if(data?.letterOfIndents?.[0]){ + const updatedLOI = data?.letterOfIndents?.[0] + const state = { + header:getResponseHeader(performedAction,updatedLOI), + id: updatedLOI?.letterOfIndentNumber, + info: t("WORKS_LOI_ID"), + message: getResponseMessage(performedAction,updatedLOI), + links: [ + { + name: t("WORKS_CREATE_NEW_LOI"), + redirectUrl: `/${window.contextPath}/employee/works/create-loi`, + code: "", + svg: "CreateEstimateIcon", + isVisible:false, + type:"add" + }, + { + name: t("WORKS_GOTO_LOI_INBOX"), + redirectUrl: `/${window.contextPath}/employee/works/LOIInbox`, + code: "", + svg: "CreateEstimateIcon", + isVisible:true, + type:"inbox" + }, + ], + responseData:data, + requestData:variables + } + history.push(`/${window.contextPath}/employee/works/response`, state) + } + if(data?.estimates?.[0]){ + const updatedEstimate = data?.estimates?.[0] + const state = { + header:getEstimateResponseHeader(performedAction,updatedEstimate), + id: updatedEstimate?.estimateNumber, + info: t("WORKS_ESTIMATE_ID"), + message: getEstimateResponseMessage(performedAction,updatedEstimate), + links: [ + { + name: t("WORKS_CREATE_ESTIMATE"), + redirectUrl: `/${window.contextPath}/employee/works/create-estimate`, + code: "", + svg: "CreateEstimateIcon", + isVisible:false, + type:"add" + }, + { + name: t("WORKS_GOTO_ESTIMATE_INBOX"), + redirectUrl: `/${window.contextPath}/employee/works/inbox`, + code: "", + svg: "RefreshIcon", + isVisible:true, + type:"inbox" + }, + ], + responseData:data, + requestData:variables + } + history.push(`/${window.contextPath}/employee/works/response`, state) + } + if (isOBPS?.bpa) { + data.selectedAction = selectedAction; + history.replace(`/${window?.contextPath}/employee/obps/response`, { data: data }); + } + if (isOBPS?.isStakeholder) { + data.selectedAction = selectedAction; + history.push(`/${window?.contextPath}/employee/obps/stakeholder-response`, { data: data }); + } + if (isOBPS?.isNoc) { + history.push(`/${window?.contextPath}/employee/noc/response`, { data: data }); + } + if (data?.Amendments?.length > 0 ){ + //RAIN-6981 instead just show a toast here with appropriate message + //show toast here and return + //history.push("/${window?.contextPath}/employee/ws/response-bill-amend", { status: true, state: data?.Amendments?.[0] }) + + if(variables?.AmendmentUpdate?.workflow?.action.includes("SEND_BACK")){ + setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_SEND_BACK_UPDATE_SUCCESS")}) + } else if (variables?.AmendmentUpdate?.workflow?.action.includes("RE-SUBMIT")){ + setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_RE_SUBMIT_UPDATE_SUCCESS") }) + } else if (variables?.AmendmentUpdate?.workflow?.action.includes("APPROVE")){ + setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_APPROVE_UPDATE_SUCCESS") }) + } + else if (variables?.AmendmentUpdate?.workflow?.action.includes("REJECT")){ + setShowToast({ key: "success", label: t("ES_MODIFYWSCONNECTION_REJECT_UPDATE_SUCCESS") }) + } + return + } + if(data?.musterRolls?.[0]) { + const musterRoll = data?.musterRolls?.[0] + const response = getAttendanceResponseHeaderAndMessage(performedAction) + const state = { + header: response?.header, + message: response?.message, + info: t("ATM_REGISTER_ID_WEEK"), + id: `${musterRoll.registerId} | ${format(new Date(musterRoll.startDate), "dd/MM/yyyy")} - ${format(new Date(musterRoll.endDate), "dd/MM/yyyy")}`, + } + history.push(`/${window.contextPath}/employee/attendencemgmt/response`, state) + } + setShowToast({ key: "success", action: selectedAction }); + clearDataDetails && setTimeout(clearDataDetails, 3000); + setTimeout(closeToast, 5000); + queryClient.clear(); + queryClient.refetchQueries("APPLICATION_SEARCH"); + //push false status when reject + + }, + }); + } + + closeModal(); + }; + + if (isLoading || isEnableLoader) { + return ; + } + + return ( + + {!isLoading ? ( + + + {showModal ? ( + + ) : null} + {isWarningPop ? ( + + ) : null} + + {showActionBar && } + + ) : ( + + )} + + ); +}; + +export default ApplicationDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh b/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh new file mode 100644 index 00000000000..4909658c697 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +BASEDIR="$(cd "$(dirname "$0")" && pwd)" + +msg() { + echo -e "\n\n\033[32;32m$1\033[0m" +} + + +# msg "Pre-building all packages" +# yarn build +# sleep 5 + +msg "Building and publishing css" +cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag campaign-1.0 + + +# msg "Building and publishing libraries" +# cd "$BASEDIR/packages/modules/workbench-hcm" && rm -rf dist && yarn&& npm publish --tag workbench-1.0 + diff --git a/frontend/micro-ui/web/micro-ui-internals/publish.sh b/frontend/micro-ui/web/micro-ui-internals/publish.sh new file mode 100644 index 00000000000..4909658c697 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/publish.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +BASEDIR="$(cd "$(dirname "$0")" && pwd)" + +msg() { + echo -e "\n\n\033[32;32m$1\033[0m" +} + + +# msg "Pre-building all packages" +# yarn build +# sleep 5 + +msg "Building and publishing css" +cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag campaign-1.0 + + +# msg "Building and publishing libraries" +# cd "$BASEDIR/packages/modules/workbench-hcm" && rm -rf dist && yarn&& npm publish --tag workbench-1.0 + diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh new file mode 100755 index 00000000000..9de72331774 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./scripts/run.sh core utilities diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh new file mode 100755 index 00000000000..5b0c7b831ed --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +curl -v -X POST https://builds.digit.org/job/builds/job/digit-ui/buildWithParameters \ + --user saurabh-egov:114cbf3df675835931688b2d3f0014a1f7 \ + --data-urlencode json='{"parameter": [{"name":"BRANCH", "value":"origin/'$1'"}]}' + +# curl https://builds.digit.org/job/builds/job/digit-ui/lastBuild/api/json | grep --color result\":null + diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh new file mode 100755 index 00000000000..a1711fec55b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./scripts/deploy.sh dev \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh new file mode 100755 index 00000000000..f00c59f13b8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +MODULES=( "components" "core" "libraries" "example" ) + +RUNARGS=() +BUILDARGS=() + +for var in "$@" +do + BUILDARGS=( ${BUILDARGS[@]} build:"$var" ) + RUNARGS=( ${RUNARGS[@]} dev:"$var" ) +done + +a=0 +while [ "$a" -lt 3 ] +do + BUILD[$a]=build:${MODULES[$a]} + a=` expr $a + 1 ` +done + +echo "BUILDING MODULES:-" ${BUILD[*]} ${BUILDARGS[*]} +yarn run-p ${BUILD[*]} ${BUILDARGS[*]} + +b=0 +while [ "$b" -lt 4 ] +do + RUN[$b]=dev:${MODULES[$b]} + b=` expr $b + 1 ` +done + +echo "SERVING MODULES:-" ${RUN[*]} ${RUNARGS[*]} +yarn run-p ${RUN[*]} ${RUNARGS[*]} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/test.js b/frontend/micro-ui/web/micro-ui-internals/test.js new file mode 100644 index 00000000000..60c958d0bac --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/test.js @@ -0,0 +1,31 @@ +const middleWare_1 = (data, _break, _next) => { + data.a = "a"; + _next(data); +}; + + +const middleWare_2 = (data, _break, _next) => { + data.b = "b"; + // _break(); + _next(data); +}; + +const middleWare_3 = (data, _break, _next) => { + data.c = "c"; + _next(data); +}; + +let middleWares = [middleWare_1, middleWare_2, middleWare_3]; + +const callMiddlewares = () => { + let applyBreak = false; + let itr = -1; + let _break = () => (applyBreak = true); + let _next = (data) => { + if (!applyBreak && ++itr < middleWares.length) middleWares[itr](data, _break, _next); + else return; + }; + _next({}); +}; + +callMiddlewares(); diff --git a/frontend/micro-ui/web/microplan/App.js b/frontend/micro-ui/web/microplan/App.js new file mode 100644 index 00000000000..afcd26669c6 --- /dev/null +++ b/frontend/micro-ui/web/microplan/App.js @@ -0,0 +1,61 @@ +import React from "react"; +import { initLibraries } from "@egovernments/digit-ui-libraries"; + +import { DigitUI } from "@egovernments/digit-ui-module-core"; + +import { UICustomizations } from "./Customisations/UICustomizations"; +import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; + + +window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + +const enabledModules = [ + "DSS", + "NDSS", + "Utilities", + "HRMS", + "Engagement", + "Workbench", + "Microplanning" +]; + +const moduleReducers = (initData) => ({ + initData, +}); + +const initDigitUI = () => { + window.Digit.ComponentRegistryService.setupRegistry({ + + }); + + + initMicroplanningComponents() + window.Digit.Customizations = { + PGR: {}, + commonUiConfig: UICustomizations, + }; +}; + +initLibraries().then(() => { + initDigitUI(); +}); + +function App() { + window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + const stateCode = + window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || + process.env.REACT_APP_STATE_LEVEL_TENANT_ID; + if (!stateCode) { + return

stateCode is not defined

; + } + return ( + + ); +} + +export default App; diff --git a/frontend/micro-ui/web/microplan/Dockerfile b/frontend/micro-ui/web/microplan/Dockerfile new file mode 100644 index 00000000000..56388b8e2d7 --- /dev/null +++ b/frontend/micro-ui/web/microplan/Dockerfile @@ -0,0 +1,30 @@ +FROM egovio/alpine-node-builder-14:yarn AS build +#FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build +RUN apk update && apk upgrade +RUN apk add --no-cache git>2.30.0 +ARG WORK_DIR +WORKDIR /app +ENV NODE_OPTIONS "--max-old-space-size=4792" + +COPY ${WORK_DIR} . +RUN ls -lah + +#RUN node web/envs.js +RUN cd web/ \ + && node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \ + && node -e 'console.log("core only")' \ + && cd microplan/ \ + && chmod +x ./install-deps.sh \ + && ./install-deps.sh \ + && cd ../ \ + && yarn install \ + && yarn build:webpack + +FROM nginx:mainline-alpine +#FROM ghcr.io/egovernments/nginx:mainline-alpine +ENV WORK_DIR=/var/web/microplan-ui + +RUN mkdir -p ${WORK_DIR} + +COPY --from=build /app/web/build ${WORK_DIR}/ +COPY --from=build /app/web/microplan/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/microplan/install-deps.sh b/frontend/micro-ui/web/microplan/install-deps.sh new file mode 100644 index 00000000000..b090c8d6f04 --- /dev/null +++ b/frontend/micro-ui/web/microplan/install-deps.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +BRANCH="$(git branch --show-current)" + +echo "Main Branch: $BRANCH" + +INTERNALS="micro-ui-internals" +cd .. + +cp microplan/App.js src +cp microplan/package.json package.json +cp microplan/webpack.config.js webpack.config.js +cp microplan/inter-package.json $INTERNALS/package.json + +cp $INTERNALS/example/src/UICustomizations.js src/Customisations + +echo "UI :: microplan " && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" + diff --git a/frontend/micro-ui/web/microplan/inter-package.json b/frontend/micro-ui/web/microplan/inter-package.json new file mode 100644 index 00000000000..635c9cc954b --- /dev/null +++ b/frontend/micro-ui/web/microplan/inter-package.json @@ -0,0 +1,61 @@ +{ + "name": "egovernments", + "version": "1.0.0", + "main": "index.js", + "workspaces": [ + "example", + "packages/css", + "packages/modules/*" + ], + "author": "JaganKumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "scripts": { + "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", + "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", + "start:dev": "run-p dev:**", + "start:script": "./scripts/create.sh", + "dev:css": "cd packages/css && yarn start", + "publish:css": "cd packages/css && yarn publish --access public", + "dev:example": "cd example && yarn start", + "dev:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn start", + "build": "run-p build:**", + "build:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn build", + "deploy:jenkins": "./scripts/jenkins.sh", + "clean": "rm -rf node_modules" + }, + "resolutions": { + "**/@babel/runtime": "7.20.1", + "**/babel-preset-react-app": "10.0.0", + "**/babel-loader": "8.2.2", + "**/@babel/core": "7.14.0", + "**/@babel/preset-env": "7.14.0", + "**/@babel/plugin-transform-modules-commonjs": "7.14.0", + "**/polished":"4.2.2", + "fast-uri":"2.1.0" + }, + "devDependencies": { + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "husky": {}, + "lint-staged": { + "*.{js,css,md}": "prettier --write" + }, + "dependencies": { + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "@egovernments/digit-ui-react-components": "1.8.1-beta.2", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0" + } +} diff --git a/frontend/micro-ui/web/microplan/nginx.conf b/frontend/micro-ui/web/microplan/nginx.conf new file mode 100644 index 00000000000..9c84c01c4be --- /dev/null +++ b/frontend/micro-ui/web/microplan/nginx.conf @@ -0,0 +1,12 @@ +server +{ + listen 80; + underscores_in_headers on; + + location /microplan-ui + { + root /var/web; + index index.html index.htm; + try_files $uri $uri/ /microplan-ui/index.html; + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/microplan/package.json b/frontend/micro-ui/web/microplan/package.json new file mode 100644 index 00000000000..dff749d1780 --- /dev/null +++ b/frontend/micro-ui/web/microplan/package.json @@ -0,0 +1,80 @@ +{ + "name": "micro-ui", + "version": "1.0.0", + "author": "Jagankumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "workspaces": [ + "micro-ui-internals/packages/modules/*" + ], + "homepage": "/microplan-ui", + "dependencies": { + "@egovernments/digit-ui-libraries": "1.8.2-beta.1", + "@egovernments/digit-ui-module-core": "1.8.2-beta.1", + "@egovernments/digit-ui-module-utilities": "1.0.1-beta.23", + "@egovernments/digit-ui-react-components": "1.8.2-beta.1", + "@egovernments/digit-ui-module-hcmmicroplanning":"0.0.1", + "@egovernments/digit-ui-components": "0.0.2-beta.2", + "babel-loader": "8.1.0", + "clean-webpack-plugin": "4.0.0", + "react": "17.0.2", + "react-dom": "17.0.2", + "jsonpath": "^1.1.1", + "react-router-dom": "5.3.0", + "react-scripts": "4.0.1", + "web-vitals": "1.1.2", + "terser-brunch": "^4.1.0", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "css-loader": "5.2.6", + "style-loader": "2.0.0", + "webpack-cli": "4.10.0" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "7.21.0", + "file-loader": "^6.2.0", + "http-proxy-middleware": "1.3.1", + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "scripts": { + "start": "react-scripts start", + "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", + "build:prepare": "./build.sh", + "build:libraries": "cd micro-ui-internals && yarn build", + "build:prod": "webpack --mode production", + "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", + "clean": "rm -rf node_modules" + }, + "eslintConfig": { + "extends": [ + "react-app" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/microplan/webpack.config.js b/frontend/micro-ui/web/microplan/webpack.config.js new file mode 100644 index 00000000000..c8036364605 --- /dev/null +++ b/frontend/micro-ui/web/microplan/webpack.config.js @@ -0,0 +1,52 @@ +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); +// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +module.exports = { + // mode: 'development', + entry: "./src/index.js", + devtool: "none", + module: { + rules: [ + { + test: /\.(js)$/, + exclude: /node_modules/, + use: ["babel-loader"], + }, + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + }, + { + test: /\.(png|jpe?g|gif)$/i, + use: [ + { + loader: 'file-loader', + }, + ], + }, + ], + }, + output: { + filename: "[name].bundle.js", + path: path.resolve(__dirname, "build"), + publicPath: "/microplan-ui/", + }, + optimization: { + splitChunks: { + chunks: 'all', + minSize:20000, + maxSize:50000, + enforceSizeThreshold:50000, + minChunks:1, + maxAsyncRequests:30, + maxInitialRequests:30 + }, + }, + plugins: [ + new CleanWebpackPlugin(), + // new BundleAnalyzerPlugin(), + new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), + ], +}; \ No newline at end of file diff --git a/frontend/micro-ui/web/package.json b/frontend/micro-ui/web/package.json new file mode 100644 index 00000000000..e90ab5a52ba --- /dev/null +++ b/frontend/micro-ui/web/package.json @@ -0,0 +1,85 @@ +{ + "name": "micro-ui", + "version": "0.1.0", + "author": "Jagankumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "workspaces": [ + "micro-ui-internals/packages/libraries", + "micro-ui-internals/packages/react-components", + "micro-ui-internals/packages/modules/*" + ], + "homepage": "/digit-ui", + "dependencies": { + "@egovernments/digit-ui-libraries": "1.8.1-beta.4", + "@egovernments/digit-ui-module-workbench": "1.0.1-beta.16", + "@egovernments/digit-ui-module-core": "1.8.2-beta.2", + "@egovernments/digit-ui-module-hrms": "1.8.0-beta.2", + "@egovernments/digit-ui-react-components": "1.8.2-beta.6", + "@egovernments/digit-ui-components": "0.0.2-beta.1", + "@egovernments/digit-ui-module-dss": "1.8.0-beta", + "@egovernments/digit-ui-module-common": "1.8.0-beta", + "@egovernments/digit-ui-module-utilities": "1.0.0-beta", + "@egovernments/digit-ui-module-engagement": "1.5.20", + "babel-loader": "8.1.0", + "clean-webpack-plugin": "4.0.0", + "react": "17.0.2", + "react-dom": "17.0.2", + "jsonpath": "^1.1.1", + "react-router-dom": "5.3.0", + "react-scripts": "4.0.1", + "web-vitals": "1.1.2", + "terser-brunch": "^4.1.0", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "css-loader": "5.2.6", + "style-loader": "2.0.0", + "webpack-cli": "4.10.0" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "7.21.0", + "http-proxy-middleware": "1.3.1", + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "scripts": { + "start": "react-scripts start", + "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", + "build:prepare": "./build.sh", + "build:libraries": "cd micro-ui-internals && yarn build", + "build:prod": "webpack --mode production", + "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", + "clean": "rm -rf node_modules" + }, + "eslintConfig": { + "extends": [ + "react-app" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/public/index.html b/frontend/micro-ui/web/public/index.html new file mode 100644 index 00000000000..661b6fa2425 --- /dev/null +++ b/frontend/micro-ui/web/public/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + DIGIT + + + + + + +
+ + + + \ No newline at end of file diff --git a/frontend/micro-ui/web/public/robots.txt b/frontend/micro-ui/web/public/robots.txt new file mode 100644 index 00000000000..e9e57dc4d41 --- /dev/null +++ b/frontend/micro-ui/web/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/frontend/micro-ui/web/src/App.js b/frontend/micro-ui/web/src/App.js new file mode 100644 index 00000000000..d871f8e8f4c --- /dev/null +++ b/frontend/micro-ui/web/src/App.js @@ -0,0 +1,74 @@ +import React from "react"; +import { initLibraries } from "@egovernments/digit-ui-libraries"; +import { + paymentConfigs, + PaymentLinks, + PaymentModule, +} from "@egovernments/digit-ui-module-common"; +import { DigitUI,initCoreComponents } from "@egovernments/digit-ui-module-core"; +import { initDSSComponents } from "@egovernments/digit-ui-module-dss"; +import { initEngagementComponents } from "@egovernments/digit-ui-module-engagement"; +import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms"; +import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; +import { UICustomizations } from "./Customisations/UICustomizations"; +import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; +// import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; + +window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + +const enabledModules = [ + "DSS", + "NDSS", + "Utilities", + "HRMS", + "Engagement", + "Workbench", + "Microplanning" +]; + +const moduleReducers = (initData) => ({ + initData, +}); + +const initDigitUI = () => { + window.Digit.ComponentRegistryService.setupRegistry({ + PaymentModule, + ...paymentConfigs, + PaymentLinks, + }); + initCoreComponents(); + initDSSComponents(); + initHRMSComponents(); + initEngagementComponents(); + initUtilitiesComponents(); + initWorkbenchComponents(); + + window.Digit.Customizations = { + PGR: {}, + commonUiConfig: UICustomizations, + }; +}; + +initLibraries().then(() => { + initDigitUI(); +}); + +function App() { + window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + const stateCode = + window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || + process.env.REACT_APP_STATE_LEVEL_TENANT_ID; + if (!stateCode) { + return

stateCode is not defined

; + } + return ( + + ); +} + +export default App; diff --git a/frontend/micro-ui/web/src/ComponentRegistry.js b/frontend/micro-ui/web/src/ComponentRegistry.js new file mode 100644 index 00000000000..9bafce3dc89 --- /dev/null +++ b/frontend/micro-ui/web/src/ComponentRegistry.js @@ -0,0 +1,11 @@ +class Registry { + constructor(registry = {}) { + this._registry = registry; + } + + getComponent(id) { + return this._registry[id]; + } +} + +export default Registry; diff --git a/frontend/micro-ui/web/src/Customisations/UICustomizations.js b/frontend/micro-ui/web/src/Customisations/UICustomizations.js new file mode 100644 index 00000000000..6d17ab0d51b --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/UICustomizations.js @@ -0,0 +1,428 @@ +import { Link } from "react-router-dom"; +import _ from "lodash"; + +//create functions here based on module name set in mdms(eg->SearchProjectConfig) +//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] +// these functions will act as middlewares +var Digit = window.Digit || {}; + + + +const businessServiceMap = { + + "muster roll": "MR" +}; + +const inboxModuleNameMap = { + "muster-roll-approval": "muster-roll-service", +}; + +export const UICustomizations = { + businessServiceMap, + updatePayload: (applicationDetails, data, action, businessService) => { + + if (businessService === businessServiceMap.estimate) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + estimate: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap.contract) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + contract: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["muster roll"]) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + musterRoll: applicationDetails, + workflow, + }; + } + if(businessService === businessServiceMap?.["works.purchase"]){ + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + const additionalFieldsToSet = { + projectId:applicationDetails.additionalDetails.projectId, + invoiceDate:applicationDetails.billDate, + invoiceNumber:applicationDetails.referenceId.split('_')?.[1], + contractNumber:applicationDetails.referenceId.split('_')?.[0], + documents:applicationDetails.additionalDetails.documents + } + return { + bill: {...applicationDetails,...additionalFieldsToSet}, + workflow, + }; + } + }, + enableModalSubmit:(businessService,action,setModalSubmit,data)=>{ + if(businessService === businessServiceMap?.["muster roll"] && action.action==="APPROVE"){ + setModalSubmit(data?.acceptTerms) + } + }, + enableHrmsSearch: (businessService, action) => { + if (businessService === businessServiceMap.estimate) { + return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); + } + if (businessService === businessServiceMap.contract) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + if (businessService === businessServiceMap?.["muster roll"]) { + return action.action.includes("VERIFY"); + } + if(businessService === businessServiceMap?.["works.purchase"]){ + return action.action.includes("VERIFY_AND_FORWARD") + } + return false; + }, + getBusinessService: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return businessServiceMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return businessServiceMap?.contract; + } else if (moduleCode?.includes("muster roll")) { + return businessServiceMap?.["muster roll"]; + } + else if (moduleCode?.includes("works.purchase")) { + return businessServiceMap?.["works.purchase"]; + } + else if (moduleCode?.includes("works.wages")) { + return businessServiceMap?.["works.wages"]; + } + else if (moduleCode?.includes("works.supervision")) { + return businessServiceMap?.["works.supervision"]; + } + else { + return businessServiceMap; + } + }, + getInboxModuleName: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return inboxModuleNameMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return inboxModuleNameMap?.contracts; + } else if (moduleCode?.includes("attendence")) { + return inboxModuleNameMap?.attendencemgmt; + } else { + return inboxModuleNameMap; + } + }, + + AttendanceInboxConfig: { + preProcess: (data) => { + + //set tenantId + data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId(); + data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + + const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim(); + if(musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber + + const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim(); + if(attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName + + // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side) + const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee); + delete data.body.inbox.moduleSearchCriteria.assignee; + if (assignee?.code === "ASSIGNED_TO_ME") { + data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid; + } + + //cloning locality and workflow states to format them + // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []); + + let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null); + delete data.body.inbox.moduleSearchCriteria.orgId; + if(selectedOrg) { + data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber; + } + + // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null); + // delete data.body.inbox.moduleSearchCriteria.ward; + // if(selectedWard) { + // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code; + // } + + let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []); + let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []); + // delete data.body.inbox.moduleSearchCriteria.locality; + delete data.body.inbox.moduleSearchCriteria.state; + delete data.body.inbox.moduleSearchCriteria.ward; + + // locality = locality?.map((row) => row?.code); + states = Object.keys(states)?.filter((key) => states[key]); + ward = ward?.map((row) => row?.code); + + + // //adding formatted data to these keys + // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality; + if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states; + if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward; + const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {}); + if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code; + + //adding tenantId to moduleSearchCriteria + data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + + //setting limit and offset becoz somehow they are not getting set in muster inbox + data.body.inbox .limit = data.state.tableForm.limit + data.body.inbox.offset = data.state.tableForm.offset + delete data.state + return data; + }, + postProcess: (responseArray, uiConfig) => { + const statusOptions = responseArray?.statusMap + ?.filter((item) => item.applicationstatus) + ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` })); + if (uiConfig?.type === "filter") { + let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus"); + if (fieldConfig.length) { + fieldConfig[0].populators.options = statusOptions; + } + } + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "ATM_MUSTER_ROLL_ID") { + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + } + if (key === "ATM_ATTENDANCE_WEEK") { + const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate( + value?.endDate, + "dd/MM/yyyy" + )}`; + return
{week}
; + } + if (key === "ATM_NO_OF_INDIVIDUALS") { + return
{value?.length}
; + } + if(key === "ATM_AMOUNT_IN_RS"){ + return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")}; + } + if (key === "ATM_SLA") { + return parseInt(value) > 0 ? ( + {t(value) || ""} + ) : ( + {t(value) || ""} + ); + } + if (key === "COMMON_WORKFLOW_STATES") { + return {t(`WF_MUSTOR_${value}`)} + } + //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default + return {t(`CASE_NOT_HANDLED`)} + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "ATM_MUSTER_ROLL_ID") + link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`; + }); + return link; + }, + populateReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + return { + url: "/org-services/organisation/v1/_search", + params: { limit: 50, offset: 0 }, + body: { + SearchCriteria: { + tenantId: tenantId, + functions : { + type : "CBO" + } + }, + }, + config: { + enabled: true, + select: (data) => { + return data?.organisations; + }, + }, + }; + }, + }, + SearchWageSeekerConfig: { + customValidationCheck: (data) => { + //checking both to and from date are present + const { createdFrom, createdTo } = data; + if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) + return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + + return false; + }, + preProcess: (data) => { + data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() }; + + let requestBody = { ...data.body.Individual }; + const pathConfig = { + name: "name.givenName", + }; + const dateConfig = { + createdFrom: "daystart", + createdTo: "dayend", + }; + const selectConfig = { + wardCode: "wardCode[0].code", + socialCategory: "socialCategory.code", + }; + const textConfig = ["name", "individualId"] + let Individual = Object.keys(requestBody) + .map((key) => { + if (selectConfig[key]) { + requestBody[key] = _.get(requestBody, selectConfig[key], null); + } else if (typeof requestBody[key] == "object") { + requestBody[key] = requestBody[key]?.code; + } else if (textConfig?.includes(key)) { + requestBody[key] = requestBody[key]?.trim() + } + return key; + }) + .filter((key) => requestBody[key]) + .reduce((acc, curr) => { + if (pathConfig[curr]) { + _.set(acc, pathConfig[curr], requestBody[curr]); + } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { + _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); + } else { + _.set(acc, curr, requestBody[curr]); + } + return acc; + }, {}); + + data.body.Individual = { ...Individual }; + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + //here we can add multiple conditions + //like if a cell is link then we return link + //first we can identify which column it belongs to then we can return relevant result + switch (key) { + case "MASTERS_WAGESEEKER_ID": + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + + case "MASTERS_SOCIAL_CATEGORY": + return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); + + case "CORE_COMMON_PROFILE_CITY": + return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); + + case "MASTERS_WARD": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + + case "MASTERS_LOCALITY": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + default: + return t("ES_COMMON_NA"); + } + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "MASTERS_WAGESEEKER_ID") + link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; + }); + return link; + }, + additionalValidations: (type, data, keys) => { + if (type === "date") { + return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; + } + } + }, +}; diff --git a/frontend/micro-ui/web/src/Customisations/index.js b/frontend/micro-ui/web/src/Customisations/index.js new file mode 100644 index 00000000000..803b1e8763e --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/index.js @@ -0,0 +1,19 @@ +import { ptComponents } from "./pt"; +import { tlComponents } from "./tl"; + +var Digit = window.Digit || {}; + +const customisedComponent = { + ...ptComponents, + ...tlComponents +} + + + +export const initCustomisationComponents = () => { + Object.entries(customisedComponent).forEach(([key, value]) => { + Digit.ComponentRegistryService.setComponent(key, value); + }); +}; + + diff --git a/frontend/micro-ui/web/src/Customisations/pt/index.js b/frontend/micro-ui/web/src/Customisations/pt/index.js new file mode 100644 index 00000000000..0063fcd4774 --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/pt/index.js @@ -0,0 +1,13 @@ +import PropertyUsageType from "./pageComponents/PropertyUsageType"; +import PTVasikaDetails from "./pageComponents/PTVasikaDetails"; +import PTAllotmentDetails from "./pageComponents/PTAllotmentDetails"; +import PTBusinessDetails from "./pageComponents/PTBusinessDetails"; + + + +export const ptComponents = { + PropertyUsageType: PropertyUsageType, + PTVasikaDetail:PTVasikaDetails, + PTAllotmentDetails:PTAllotmentDetails, + PTBusinessDetails:PTBusinessDetails +}; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js new file mode 100644 index 00000000000..569aa45e409 --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js @@ -0,0 +1,64 @@ +import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; +import React, { useState } from "react"; +var validation ={}; +const PTAllotmentDetails = ({ t, config, onSelect, value, userType, formData }) => { + + const [ + val, setValue + ] = useState(formData?.[config.key]?.alotmentDetails||""); + + const goNext = () => { + onSelect(config.key, {alotmentDetails:val}); + }; + + + if (userType === "employee") { + return ( + + + {t("PT_VASIKA_NO_LABEL") } +
+ setValue(e?.target?.value)} + // autoFocus={presentInModifyApplication} + /> +
+
+
+ ); + } + return ( + + +
+ {`${t("PT_VASIKA_ALLOTMENT_LABEL")}`} + setValue(e?.target?.value)} + + /> +
+
+ {} +
+ ); +}; + +export default PTAllotmentDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js new file mode 100644 index 00000000000..3d28785e7e5 --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js @@ -0,0 +1,68 @@ +import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; +import React, { useState } from "react"; +var validation ={}; +const PTBusinessDetails = ({ t, config, onSelect, value, userType, formData }) => { + + + const [ + val, setValue + ] = useState(formData?.[config.key]?.businessDetails||""); + + const goNext = () => { + onSelect(config.key, {businessDetails:val}); + }; + + + if (userType === "employee") { + return ( + + + {t("PT_VASIKA_NO_LABEL") } +
+ setValue(e?.target?.value)} + // autoFocus={presentInModifyApplication} + /> +
+
+ +
+ ); + } + return ( + + + +
+ {`${t("PT_VASIKA_BUS_DETAILS_LABEL")}`} + setValue(e?.target?.value)} + + /> +
+ +
+ {} +
+ ); +}; + +export default PTBusinessDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js new file mode 100644 index 00000000000..0e4b6895745 --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js @@ -0,0 +1,79 @@ +import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; +import React, { useState } from "react"; +var validation ={}; +const PTVasikaDetails = ({ t, config, onSelect, value, userType, formData }) => { + + + const [ + val, setValue + ] = useState(formData?.[config.key]?.vasikaNo||""); + const [ + other, setOther + ] = useState(formData?.[config.key]?.vasikaArea||""); + const goNext = () => { + onSelect(config.key, {vasikaNo:val,vasikaArea:other}); + }; + + + if (userType === "employee") { + return ( + + + {t("PT_VASIKA_NO_LABEL") } +
+ setValue(e?.target?.value)} + // autoFocus={presentInModifyApplication} + /> +
+
+ +
+ ); + } + return ( + + + +
+ {`${t("PT_VASIKA_NO_LABEL")}`} + setValue(e?.target?.value)} + + /> +
+ {`${t("PT_VASIKA_AREA_LABEL")}`} + setOther(e?.target?.value)} + /> +
+ {} +
+ ); +}; + +export default PTVasikaDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js new file mode 100644 index 00000000000..deade4fc2ad --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js @@ -0,0 +1,134 @@ +import { + CardLabel, CardLabelError, CitizenInfoLabel, Dropdown, FormStep, LabelFieldPair, RadioButtons +} from "@egovernments/digit-ui-react-components"; +import React, { useEffect, useState } from "react"; +import { useLocation } from "react-router-dom"; + +var Digit = window.Digit || {}; + +const PropertyUsageType = ({ t, config, onSelect, userType, formData, formState, setError, clearErrors, onBlur }) => { + const [usageCategoryMajor, setPropertyPurpose] = useState( + formData?.usageCategoryMajor && formData?.usageCategoryMajor?.code === "NONRESIDENTIAL.OTHERS" + ? { code: `${formData?.usageCategoryMajor?.code}`, i18nKey: `PROPERTYTAX_BILLING_SLAB_OTHERS` } + : formData?.usageCategoryMajor + ); + + const tenantId = Digit.ULBService.getCurrentTenantId(); + const stateId = tenantId.split(".")[0]; + const { data: Menu = { }, isLoading: menuLoading } = Digit.Hooks.pt.usePropertyMDMS(stateId, "PropertyTax", "UsageCategory") || { }; + let usagecat = []; + usagecat = Menu?.PropertyTax?.UsageCategory || []; + let i; + let menu = []; + + const { pathname } = useLocation(); + const presentInModifyApplication = pathname.includes("modify"); + + function usageCategoryMajorMenu(usagecat) { + if (userType === "employee") { + const catMenu = usagecat + ?.filter((e) => e?.code.split(".").length <= 2 && e.code !== "NONRESIDENTIAL") + ?.map((item) => { + const arr = item?.code.split("."); + if (arr.length == 2) return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + arr[1], code: item?.code }; + else return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + item?.code, code: item?.code }; + }); + return catMenu; + } else { + for (i = 0; i < 10; i++) { + if ( + Array.isArray(usagecat) && + usagecat.length > 0 && + usagecat[i].code.split(".")[0] == "NONRESIDENTIAL" && + usagecat[i].code.split(".").length == 2 + ) { + menu.push({ i18nKey: "PROPERTYTAX_BILLING_SLAB_" + usagecat[i].code.split(".")[1], code: usagecat[i].code }); + } + } + return menu; + } + } + + useEffect(() => { + if (!menuLoading && presentInModifyApplication && userType === "employee") { + const original = formData?.originalData?.usageCategory; + const selectedOption = usageCategoryMajorMenu(usagecat).filter((e) => e.code === original)[0]; + setPropertyPurpose(selectedOption); + } + }, [menuLoading]); + + const onSkip = () => onSelect(); + + + function selectPropertyPurpose(value) { + setPropertyPurpose(value); + } + + function goNext() { + if (usageCategoryMajor?.i18nKey === "PROPERTYTAX_BILLING_SLAB_OTHERS") { + usageCategoryMajor.i18nKey = "PROPERTYTAX_BILLING_SLAB_NONRESIDENTIAL"; + onSelect(config.key, usageCategoryMajor); + } else { + onSelect(config.key, usageCategoryMajor); + } + } + + useEffect(() => { + if (userType === "employee") { + if (!usageCategoryMajor) { + setError(config.key, { type: "required", message: t(`CORE_COMMON_REQUIRED_ERRMSG`) }); + } else { + clearErrors(config.key); + } + goNext(); + } + }, [usageCategoryMajor]); + + if (userType === "employee") { + return ( + + + {t("PT_ASSESMENT_INFO_USAGE_TYPE") + " *"} + { + selectPropertyPurpose(e); + }} + optionKey="i18nKey" + onBlur={onBlur} + t={t} + /> + + {formState.touched[config.key] ? ( + + {formState.errors?.[config.key]?.message} + + ) : null} + + ); + } + + return ( + + +
+ +
+
+ {} +
+ ); +}; + +export default PropertyUsageType; diff --git a/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js b/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js new file mode 100644 index 00000000000..642acc52090 --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js @@ -0,0 +1,5 @@ +export const TLCustomisations = { + customiseCreateFormData: (formData, licenceObject) => licenceObject, + customiseRenewalCreateFormData: (formData, licenceObject) => licenceObject, + customiseSendbackFormData: (formData, licenceObject) => licenceObject +} \ No newline at end of file diff --git a/frontend/micro-ui/web/src/Customisations/tl/index.js b/frontend/micro-ui/web/src/Customisations/tl/index.js new file mode 100644 index 00000000000..fe2ae4f4e6a --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/tl/index.js @@ -0,0 +1,7 @@ +import TLUsageType from "./pageComponents/PropertyUsageType"; + + + +export const tlComponents = { + TLPropertyUsageType: TLUsageType, +}; diff --git a/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js b/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js new file mode 100644 index 00000000000..5520a66fc5a --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js @@ -0,0 +1,136 @@ +import { + CardLabel, CardLabelError, CitizenInfoLabel, Dropdown, FormStep, LabelFieldPair, RadioButtons +} from "@egovernments/digit-ui-react-components"; +import React, { useEffect, useState } from "react"; +import { useLocation } from "react-router-dom"; + +var Digit = window.Digit || {}; + +const TLUsageType = ({ t, config, onSelect, userType, formData, formState, setError, clearErrors, onBlur }) => { + const [usageCategoryMajor, setPropertyPurpose] = useState( + formData?.usageCategoryMajor && formData?.usageCategoryMajor?.code === "NONRESIDENTIAL.OTHERS" + ? { code: `${formData?.usageCategoryMajor?.code}`, i18nKey: `PROPERTYTAX_BILLING_SLAB_OTHERS` } + : formData?.usageCategoryMajor + ); + + const tenantId = Digit.ULBService.getCurrentTenantId(); + const stateId = tenantId.split(".")[0]; + const { data: Menu = { }, isLoading: menuLoading } = Digit.Hooks.pt.usePropertyMDMS(stateId, "PropertyTax", "UsageCategory") || { }; + let usagecat = []; + usagecat = Menu?.PropertyTax?.UsageCategory || []; + let i; + let menu = []; + + const { pathname } = useLocation(); + const presentInModifyApplication = pathname.includes("modify"); + + function usageCategoryMajorMenu(usagecat) { + if (userType === "employee") { + const catMenu = usagecat + ?.filter((e) => e?.code.split(".").length <= 2 && e.code !== "NONRESIDENTIAL") + ?.map((item) => { + const arr = item?.code.split("."); + if (arr.length == 2) return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + arr[1], code: item?.code }; + else return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + item?.code, code: item?.code }; + }); + return catMenu; + } else { + for (i = 0; i < 10; i++) { + if ( + Array.isArray(usagecat) && + usagecat.length > 0 && + usagecat[i].code.split(".")[0] == "NONRESIDENTIAL" && + usagecat[i].code.split(".").length == 2 + ) { + menu.push({ i18nKey: "PROPERTYTAX_BILLING_SLAB_" + usagecat[i].code.split(".")[1], code: usagecat[i].code }); + } + } + return menu; + } + } + + useEffect(() => { + if (!menuLoading && presentInModifyApplication && userType === "employee") { + const original = formData?.originalData?.usageCategory; + const selectedOption = usageCategoryMajorMenu(usagecat).filter((e) => e.code === original)[0]; + setPropertyPurpose(selectedOption); + } + }, [menuLoading]); + + const onSkip = () => onSelect(); + + + function selectPropertyPurpose(value) { + setPropertyPurpose(value); + } + + function goNext() { + if (usageCategoryMajor?.i18nKey === "PROPERTYTAX_BILLING_SLAB_OTHERS") { + usageCategoryMajor.i18nKey = "PROPERTYTAX_BILLING_SLAB_NONRESIDENTIAL"; + onSelect(config.key, usageCategoryMajor); + } else { + onSelect(config.key, usageCategoryMajor); + } + } + + useEffect(() => { + if (userType === "employee") { + if (!usageCategoryMajor) { + setError(config.key, { type: "required", message: t(`CORE_COMMON_REQUIRED_ERRMSG`) }); + } else { + clearErrors(config.key); + } + goNext(); + } + }, [usageCategoryMajor]); + + if (userType === "employee") { + return ( + + + {t("PT_ASSESMENT_INFO_USAGE_TYPE") + " *"} + { + selectPropertyPurpose(e); + }} + optionKey="i18nKey" + onBlur={onBlur} + t={t} + /> + + {formState.touched[config.key] ? ( + + {formState.errors?.[config.key]?.message} + + ) : null} + + ); + } + + return ( + + +
+ + + +
+
+ {} +
+ ); +}; + +export default TLUsageType; diff --git a/frontend/micro-ui/web/src/index.css b/frontend/micro-ui/web/src/index.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frontend/micro-ui/web/src/index.js b/frontend/micro-ui/web/src/index.js new file mode 100644 index 00000000000..9f20bf1b506 --- /dev/null +++ b/frontend/micro-ui/web/src/index.js @@ -0,0 +1,62 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { initLibraries } from "@egovernments/digit-ui-libraries"; +import "./index.css"; +import App from './App'; +import { TLCustomisations } from './Customisations/tl/TLCustomisation'; + + +initLibraries(); + + +window.Digit.Customizations = { PGR: {} ,TL:TLCustomisations}; + +const user = window.Digit.SessionStorage.get("User"); + +if (!user || !user.access_token || !user.info) { + // login detection + + const parseValue = (value) => { + try { + return JSON.parse(value) + } catch (e) { + return value + } + } + + const getFromStorage = (key) => { + const value = window.localStorage.getItem(key); + return value && value !== "undefined" ? parseValue(value) : null; + } + + const token = getFromStorage("token") + + const citizenToken = getFromStorage("Citizen.token") + const citizenInfo = getFromStorage("Citizen.user-info") + const citizenTenantId = getFromStorage("Citizen.tenant-id") + + const employeeToken = getFromStorage("Employee.token") + const employeeInfo = getFromStorage("Employee.user-info") + const employeeTenantId = getFromStorage("Employee.tenant-id") + const userType = token === citizenToken ? "citizen" : "employee"; + + window.Digit.SessionStorage.set("user_type", userType); + window.Digit.SessionStorage.set("userType", userType); + + const getUserDetails = (access_token, info) => ({ token: access_token, access_token, info }) + + const userDetails = userType === "citizen" ? getUserDetails(citizenToken, citizenInfo) : getUserDetails(employeeToken, employeeInfo) + + window.Digit.SessionStorage.set("User", userDetails); + window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); + window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); + // end +} + +ReactDOM.render( + + + , + document.getElementById('root') +); + diff --git a/frontend/micro-ui/web/src/setupProxy.js b/frontend/micro-ui/web/src/setupProxy.js new file mode 100644 index 00000000000..1b8eda94a19 --- /dev/null +++ b/frontend/micro-ui/web/src/setupProxy.js @@ -0,0 +1,30 @@ +const { createProxyMiddleware } = require("http-proxy-middleware"); +const createProxy = createProxyMiddleware({ + target: process.env.REACT_APP_PROXY_URL, + changeOrigin: true, +}); +module.exports = function (app) { + [ + "/egov-mdms-service", + "/egov-location", + "/localization", + "/egov-workflow-v2", + "/pgr-services", + "/filestore", + "/egov-hrms", + "/user-otp", + "/user", + "/fsm", + "/billing-service", + "/collection-services", + "/pdf-service", + "/pg-service", + "/vehicle", + "/vendor", + "/property-services", + "/fsm-calculator/v1/billingSlab/_search", + "/muster-roll" + ].forEach((location) => + app.use(location, createProxy) + ); +}; diff --git a/frontend/micro-ui/web/webpack.config.js b/frontend/micro-ui/web/webpack.config.js new file mode 100644 index 00000000000..5f3dc46967a --- /dev/null +++ b/frontend/micro-ui/web/webpack.config.js @@ -0,0 +1,43 @@ +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); +// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +module.exports = { + // mode: 'development', + entry: "./src/index.js", + devtool: "none", + module: { + rules: [ + { + test: /\.(js)$/, + use: ["babel-loader"], + }, + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + } + ], + }, + output: { + filename: "[name].bundle.js", + path: path.resolve(__dirname, "build"), + publicPath: "/digit-ui/", + }, + optimization: { + splitChunks: { + chunks: 'all', + minSize:20000, + maxSize:50000, + enforceSizeThreshold:50000, + minChunks:1, + maxAsyncRequests:30, + maxInitialRequests:30 + }, + }, + plugins: [ + new CleanWebpackPlugin(), + // new BundleAnalyzerPlugin(), + new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), + ], +}; \ No newline at end of file diff --git a/frontend/micro-ui/web/workbench/App.js b/frontend/micro-ui/web/workbench/App.js new file mode 100644 index 00000000000..93b15440c5e --- /dev/null +++ b/frontend/micro-ui/web/workbench/App.js @@ -0,0 +1,72 @@ +/** + * The above code initializes various Digit UI modules and components, sets up customizations, and + * renders the DigitUI component based on the enabled modules and state code. + * @returns The `App` component is being returned, which renders the `DigitUI` component with the + * specified props such as `stateCode`, `enabledModules`, `moduleReducers`, and `defaultLanding`. The + * `DigitUI` component is responsible for rendering the UI based on the provided configuration and + * modules. + */ +import React from "react"; +import { initLibraries } from "@egovernments/digit-ui-libraries"; +import { DigitUI } from "@egovernments/digit-ui-module-core"; +// import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms"; +import { UICustomizations } from "./Customisations/UICustomizations"; +import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; +import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; +import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; +import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager" + +window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + +const enabledModules = [ + "DSS", + "NDSS", + "Utilities", + // "HRMS", + "Engagement", + "Workbench", + "HCMWORKBENCH", + "Campaign" +]; + +const moduleReducers = (initData) => ({ + initData, +}); + +const initDigitUI = () => { + window.Digit.ComponentRegistryService.setupRegistry({}); + window.Digit.Customizations = { + PGR: {}, + commonUiConfig: UICustomizations, + }; + // initHRMSComponents(); + initUtilitiesComponents(); + initWorkbenchComponents(); + initWorkbenchHCMComponents(); + initCampaignComponents(); + +}; + +initLibraries().then(() => { + initDigitUI(); +}); + +function App() { + window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + const stateCode = + window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || + process.env.REACT_APP_STATE_LEVEL_TENANT_ID; + if (!stateCode) { + return

stateCode is not defined

; + } + return ( + + ); +} + +export default App; diff --git a/frontend/micro-ui/web/workbench/Dockerfile b/frontend/micro-ui/web/workbench/Dockerfile new file mode 100644 index 00000000000..31b3912759b --- /dev/null +++ b/frontend/micro-ui/web/workbench/Dockerfile @@ -0,0 +1,29 @@ +FROM egovio/alpine-node-builder-14:yarn AS build +#FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build +RUN apk update && apk upgrade +RUN apk add --no-cache git>2.30.0 +ARG WORK_DIR +WORKDIR /app +ENV NODE_OPTIONS "--max-old-space-size=4792" + +COPY ${WORK_DIR} . +RUN ls -lah + +#RUN node web/envs.js +RUN cd web/ \ + && node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \ + && node -e 'console.log("core only")' \ + && cd workbench/ \ + && ./install-deps.sh \ + && cd ../ \ + && yarn install \ + && yarn build:webpack + +FROM nginx:mainline-alpine +#FROM ghcr.io/egovernments/nginx:mainline-alpine +ENV WORK_DIR=/var/web/workbench-ui + +RUN mkdir -p ${WORK_DIR} + +COPY --from=build /app/web/build ${WORK_DIR}/ +COPY --from=build /app/web/workbench/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/workbench/install-deps.sh b/frontend/micro-ui/web/workbench/install-deps.sh new file mode 100755 index 00000000000..54b8a4c3d7f --- /dev/null +++ b/frontend/micro-ui/web/workbench/install-deps.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +BRANCH="$(git branch --show-current)" + +echo "Main Branch: $BRANCH" + +INTERNALS="micro-ui-internals" +cd .. + +cp workbench/App.js src +cp workbench/package.json package.json +cp workbench/webpack.config.js webpack.config.js +cp workbench/inter-package.json $INTERNALS/package.json + +cp $INTERNALS/example/src/UICustomizations.js src/Customisations + +echo "UI :: workbench " && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" + diff --git a/frontend/micro-ui/web/workbench/inter-package.json b/frontend/micro-ui/web/workbench/inter-package.json new file mode 100644 index 00000000000..5216443ec23 --- /dev/null +++ b/frontend/micro-ui/web/workbench/inter-package.json @@ -0,0 +1,58 @@ +{ + "name": "egovernments", + "version": "1.0.0", + "main": "index.js", + "workspaces": [ + "example", + "packages/css", + "packages/modules/*" + ], + "author": "JaganKumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "scripts": { + "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", + "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", + "start:dev": "run-p dev:**", + "start:script": "./scripts/create.sh", + "dev:css": "cd packages/css && yarn start", + "publish:css": "cd packages/css && yarn publish --access public", + "dev:example": "cd example && yarn start", + "dev:campaign": "cd packages/modules/campaign-manager && yarn start", + "build": "run-p build:**", + "build:campaign": "cd packages/modules/campaign-manager && yarn build", + "deploy:jenkins": "./scripts/jenkins.sh", + "clean": "rm -rf node_modules" + }, + "resolutions": { + "**/@babel/runtime": "7.20.1", + "**/babel-preset-react-app": "10.0.0", + "**/ajv": "8.11.2", + "fast-uri":"2.1.0" + }, + "devDependencies": { + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "husky": {}, + "lint-staged": { + "*.{js,css,md}": "prettier --write" + }, + "dependencies": { + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "@egovernments/digit-ui-react-components": "1.8.2-beta.1", + "@egovernments/digit-ui-components": "0.0.2-beta.1", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0" + } +} diff --git a/frontend/micro-ui/web/workbench/nginx.conf b/frontend/micro-ui/web/workbench/nginx.conf new file mode 100644 index 00000000000..974ef82f241 --- /dev/null +++ b/frontend/micro-ui/web/workbench/nginx.conf @@ -0,0 +1,12 @@ +server +{ + listen 80; + underscores_in_headers on; + + location /workbench-ui + { + root /var/web; + index index.html index.htm; + try_files $uri $uri/ /workbench-ui/index.html; + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/workbench/package.json b/frontend/micro-ui/web/workbench/package.json new file mode 100644 index 00000000000..7cc60ef7bff --- /dev/null +++ b/frontend/micro-ui/web/workbench/package.json @@ -0,0 +1,89 @@ +{ + "name": "micro-ui", + "version": "1.0.0", + "author": "Jagankumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "workspaces": [ + "micro-ui-internals/packages/modules/*" + ], + "homepage": "/workbench-ui", + "dependencies": { + "@egovernments/digit-ui-libraries": "1.8.2-beta.1", + "@egovernments/digit-ui-module-workbench": "1.0.2-beta.3", + "@egovernments/digit-ui-components": "0.0.2-beta.1", + "@egovernments/digit-ui-module-core": "1.8.2-beta.2", + "@egovernments/digit-ui-module-utilities": "1.0.1-beta.30", + "@egovernments/digit-ui-react-components": "1.8.2-beta.6", + "@egovernments/digit-ui-module-hcmworkbench":"0.0.38", + "@egovernments/digit-ui-module-campaign-manager": "0.0.1", + "babel-loader": "8.1.0", + "clean-webpack-plugin": "4.0.0", + "react": "17.0.2", + "react-dom": "17.0.2", + "jsonpath": "^1.1.1", + "react-router-dom": "5.3.0", + "react-scripts": "4.0.1", + "web-vitals": "1.1.2", + "terser-brunch": "^4.1.0", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "css-loader": "5.2.6", + "style-loader": "2.0.0", + "webpack-cli": "4.10.0" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "7.21.0", + "http-proxy-middleware": "1.3.1", + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "resolutions": { + "**/babel-loader": "8.2.2", + "**/@babel/core": "7.14.0", + "**/@babel/preset-env": "7.14.0", + "**/@babel/plugin-transform-modules-commonjs": "7.14.0", + "**/polished":"4.2.2", + "fast-uri":"2.1.0" + }, + "scripts": { + "start": "react-scripts start", + "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", + "build:prepare": "./build.sh", + "build:libraries": "cd micro-ui-internals && yarn build", + "build:prod": "webpack --mode production", + "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", + "clean": "rm -rf node_modules" + }, + "eslintConfig": { + "extends": [ + "react-app" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/frontend/micro-ui/web/workbench/webpack.config.js b/frontend/micro-ui/web/workbench/webpack.config.js new file mode 100644 index 00000000000..c19e631fe01 --- /dev/null +++ b/frontend/micro-ui/web/workbench/webpack.config.js @@ -0,0 +1,44 @@ +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); +// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +module.exports = { + // mode: 'development', + entry: "./src/index.js", + devtool: "none", + module: { + rules: [ + { + test: /\.(js)$/, + exclude: /node_modules/, + use: ["babel-loader"], + }, + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + } + ], + }, + output: { + filename: "[name].bundle.js", + path: path.resolve(__dirname, "build"), + publicPath: "/workbench-ui/", + }, + optimization: { + splitChunks: { + chunks: 'all', + minSize:20000, + maxSize:50000, + enforceSizeThreshold:50000, + minChunks:1, + maxAsyncRequests:30, + maxInitialRequests:30 + }, + }, + plugins: [ + new CleanWebpackPlugin(), + // new BundleAnalyzerPlugin(), + new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), + ], +}; \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java b/health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java index 7edac5005dd..01612d5d98a 100644 --- a/health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java +++ b/health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java @@ -36,8 +36,8 @@ public CensusRowMapper(QueryUtil queryUtil) { @Override public List extractData(ResultSet rs) throws SQLException, DataAccessException { Map censusMap = new LinkedHashMap<>(); - Set populationByDemographicSet = new HashSet<>(); - Set additionalFieldSet = new HashSet<>(); + Map populationByDemographicMap = new LinkedHashMap<>(); + Map additionalFieldMap = new LinkedHashMap<>(); while (rs.next()) { String censusId = rs.getString("census_id"); @@ -45,8 +45,6 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExc if (ObjectUtils.isEmpty(censusEntry)) { censusEntry = new Census(); - populationByDemographicSet.clear(); - additionalFieldSet.clear(); // Prepare audit details AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("census_created_by")).createdTime(rs.getLong("census_created_time")).lastModifiedBy(rs.getString("census_last_modified_by")).lastModifiedTime(rs.getLong("census_last_modified_time")).build(); @@ -71,8 +69,8 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExc censusEntry.setAdditionalDetails(queryUtil.parseJson((PGobject) rs.getObject("census_additional_details"))); censusEntry.setAuditDetails(auditDetails); } - addPopulationByDemographic(rs, populationByDemographicSet, censusEntry); - addAdditionalField(rs, additionalFieldSet, censusEntry); + addPopulationByDemographic(rs, populationByDemographicMap, censusEntry); + addAdditionalField(rs, additionalFieldMap, censusEntry); censusMap.put(censusId, censusEntry); } @@ -84,14 +82,14 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExc * Adds a AdditionalField object to the census entry based on the result set. * * @param rs The ResultSet containing the data. - * @param additionalFieldSet A set to keep track of added AdditionalField objects. + * @param additionalFieldMap A map to keep track of added AdditionalField objects. * @param censusEntry The Census entry to which the AdditionalField object will be added. * @throws SQLException If an SQL error occurs. */ - private void addAdditionalField(ResultSet rs, Set additionalFieldSet, Census censusEntry) throws SQLException { + private void addAdditionalField(ResultSet rs, Map additionalFieldMap, Census censusEntry) throws SQLException { String additionalFieldId = rs.getString("additional_field_id"); - if (ObjectUtils.isEmpty(additionalFieldId) || additionalFieldSet.contains(additionalFieldId)) { + if (ObjectUtils.isEmpty(additionalFieldId) || additionalFieldMap.containsKey(additionalFieldId)) { return; } @@ -111,7 +109,7 @@ private void addAdditionalField(ResultSet rs, Set additionalFieldSet, Ce censusEntry.getAdditionalFields().add(additionalField); } - additionalFieldSet.add(additionalFieldId); + additionalFieldMap.put(additionalFieldId, additionalField); } @@ -119,14 +117,14 @@ private void addAdditionalField(ResultSet rs, Set additionalFieldSet, Ce * Adds a PopulationByDemographics object to the census entry based on the result set. * * @param rs The ResultSet containing the data. - * @param populationByDemographicSet A set to keep track of added PopulationByDemographics objects. + * @param populationByDemographicMap A map to keep track of added PopulationByDemographics objects. * @param censusEntry The Census entry to which the PopulationByDemographics object will be added. * @throws SQLException If an SQL error occurs. */ - private void addPopulationByDemographic(ResultSet rs, Set populationByDemographicSet, Census censusEntry) throws SQLException { + private void addPopulationByDemographic(ResultSet rs, Map populationByDemographicMap, Census censusEntry) throws SQLException { String populationByDemographicId = rs.getString("population_by_demographics_id"); - if (ObjectUtils.isEmpty(populationByDemographicId) || populationByDemographicSet.contains(populationByDemographicId)) { + if (ObjectUtils.isEmpty(populationByDemographicId) || populationByDemographicMap.containsKey(populationByDemographicId)) { return; } @@ -143,6 +141,6 @@ private void addPopulationByDemographic(ResultSet rs, Set populationByDe censusEntry.getPopulationByDemographics().add(populationByDemographic); } - populationByDemographicSet.add(populationByDemographicId); + populationByDemographicMap.put(populationByDemographicId, populationByDemographic); } } diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index b0a2d7d2cad..1eb0038656a 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.20-SNAPSHOT + 1.0.17-SNAPSHOT org.egov.common health-services-models - 1.0.23-SNAPSHOT + 1.0.20-SNAPSHOT compile diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java b/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java index 2d6b0fd9a6a..482ac988b98 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java @@ -5,7 +5,6 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilitySearch; import org.egov.common.producer.Producer; @@ -24,7 +23,6 @@ import java.util.Optional; import java.util.stream.Collectors; -import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @@ -37,7 +35,7 @@ public FacilityRepository(Producer producer, NamedParameterJdbcTemplate namedPar facilityRowMapper, Optional.of("facility")); } - public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { + public List findById(List ids, String columnName, Boolean includeDeleted) { List objFound = findInCache(ids); if (!includeDeleted) { objFound = objFound.stream() @@ -50,7 +48,7 @@ public SearchResponse findById(List ids, String columnName, Bo .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); if (ids.isEmpty()) { - return SearchResponse.builder().response(objFound).build(); + return objFound; } } @@ -63,12 +61,10 @@ public SearchResponse findById(List ids, String columnName, Bo objFound.addAll(this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper)); putInCache(objFound); - - /*The totalCount is being set automatically through the builder method.*/ - return SearchResponse.builder().response(objFound).build(); + return objFound; } - public SearchResponse find(FacilitySearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + public List find(FacilitySearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM facility f LEFT JOIN address a ON f.addressid = a.id"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -87,17 +83,12 @@ public SearchResponse find(FacilitySearch searchObject, Integer limit, if (lastChangedSince != null) { query = query + "and lastModifiedTime>=:lastModifiedTime "; } + query = query + "ORDER BY f.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); - - Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); - - query = query + " LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); - List facilities = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); - - return SearchResponse.builder().response(facilities).totalCount(totalCount).build(); + return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); } } diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index 73276c91d88..3517293adcf 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.facility.Address; import org.egov.common.models.facility.AddressType; diff --git a/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java b/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java index 76ceb67033d..769aae4b725 100644 --- a/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java +++ b/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java @@ -1,16 +1,13 @@ package org.egov.facility.service; -import io.micrometer.core.instrument.search.Search; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; import org.egov.common.models.facility.FacilityRequest; import org.egov.common.models.facility.FacilitySearchRequest; -import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.validator.Validator; import org.egov.facility.config.FacilityConfiguration; import org.egov.facility.repository.FacilityRepository; @@ -176,27 +173,23 @@ public List delete(FacilityBulkRequest request, boolean isBulk) { return validEntities; } - public SearchResponse search(FacilitySearchRequest facilitySearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public List search(FacilitySearchRequest facilitySearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("starting search method for facility"); String idFieldName = getIdFieldName(facilitySearchRequest.getFacility()); if (isSearchByIdOnly(facilitySearchRequest.getFacility(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(facilitySearchRequest.getFacility())), facilitySearchRequest.getFacility()); - SearchResponse searchResponse = facilityRepository.findById(ids, idFieldName, includeDeleted); - List facilities = searchResponse.getResponse().stream() + return facilityRepository.findById(ids, idFieldName, includeDeleted).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); - searchResponse.setResponse(facilities); - - return searchResponse; } log.info("completed search method for facility"); diff --git a/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java b/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java index 2857a038490..c666d6b3264 100644 --- a/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java +++ b/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java @@ -50,7 +50,7 @@ public Map> validate(FacilityBulkRequest request) { Map eMap = getIdToObjMap(validEntities, idMethod); if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); - List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false).getResponse(); + List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false); List nonExistentEntities = checkNonExistentEntities(eMap, existingEntities, idMethod); nonExistentEntities.forEach(facility -> { diff --git a/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java b/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java index 17adda2b3f2..df76ac89fe4 100644 --- a/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java +++ b/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java @@ -47,7 +47,7 @@ public Map> validate(FacilityBulkRequest request) { Map eMap = getIdToObjMap(validEntities, idMethod); if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); - List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false).getResponse(); + List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); entitiesWithMismatchedRowVersion.forEach(facility -> { diff --git a/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java b/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java index 67de20615b1..3ca37071ca8 100644 --- a/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java +++ b/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java @@ -8,7 +8,6 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; @@ -112,7 +111,7 @@ public ResponseEntity facilityV1SearchPost( @Valid @ModelAttribute URLParams urlParams, @ApiParam(value = "Details for existing facility.", required = true) @Valid @RequestBody FacilitySearchRequest request ) throws Exception { - SearchResponse searchResponse = facilityService.search( + List facilities = facilityService.search( request, urlParams.getLimit(), urlParams.getOffset(), @@ -120,9 +119,7 @@ public ResponseEntity facilityV1SearchPost( urlParams.getLastChangedSince(), urlParams.getIncludeDeleted()); FacilityBulkResponse response = FacilityBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .facilities(searchResponse.getResponse()) - .totalCount(searchResponse.getTotalCount()).build(); + .createResponseInfo(request.getRequestInfo(), true)).facilities(facilities).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java b/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java index 06955011bc0..a6e8c05f7c1 100644 --- a/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java +++ b/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java @@ -1,10 +1,8 @@ package org.egov.facility.validator; import org.egov.common.models.Error; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; -import org.egov.common.models.household.Household; import org.egov.facility.helper.FacilityBulkRequestTestBuilder; import org.egov.facility.helper.FacilityTestBuilder; import org.egov.facility.repository.FacilityRepository; @@ -39,7 +37,7 @@ class NonExistentEntityValidatorTest { void shouldAddToErrorDetailsMapIfEntityNotFound() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(SearchResponse.builder().build()); + .thenReturn(Collections.emptyList()); Map> errorDetailsMap = fNonExistentValidator.validate(request); @@ -51,9 +49,7 @@ void shouldAddToErrorDetailsMapIfEntityNotFound() { void shouldNotAddToErrorDetailsMapIfEntityFound() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(SearchResponse.builder(). - response(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())) - .build()); + .thenReturn(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())); Map> errorDetailsMap = fNonExistentValidator.validate(request); diff --git a/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java b/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java index 52f92421c49..1f44a89f94a 100644 --- a/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java +++ b/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java @@ -1,7 +1,6 @@ package org.egov.facility.validator; import org.egov.common.models.Error; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; import org.egov.facility.helper.FacilityBulkRequestTestBuilder; @@ -40,9 +39,7 @@ void shouldAddToErrorDetailsIfRowVersionMismatchFound() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); request.getFacilities().get(0).setRowVersion(2); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(SearchResponse.builder() - .response(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())) - .build()); + .thenReturn(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())); Map> errorDetailsMap = fRowVersionValidator.validate(request); @@ -54,8 +51,7 @@ void shouldAddToErrorDetailsIfRowVersionMismatchFound() { void shouldNotAddToErrorDetailsIfRowVersionSimilar() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(SearchResponse.builder() - .response(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())).build()); + .thenReturn(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())); Map> errorDetailsMap = fRowVersionValidator.validate(request); diff --git a/health-services/household/CHANGELOG.md b/health-services/household/CHANGELOG.md index 3b9cbec0526..3eed6ddb78c 100644 --- a/health-services/household/CHANGELOG.md +++ b/health-services/household/CHANGELOG.md @@ -1,12 +1,7 @@ All notable changes to this module will be documented in this file. -## 1.1.4 - 2024-08-29 - -- Added `ExistentEntityValidator` fixes - -## 1.1.3 - 2024-05-29 - -- Integrated Core 2.9 LTS +## 1.1.3 - 2024-05-29 +- Integrated Core 2.9LTS - Client reference ID validation added - Upgraded to health models 1.0.20 and health common 1.0.16 - Boundary v2 Integration @@ -16,9 +11,8 @@ All notable changes to this module will be documented in this file. - Upgraded Flyway-Core to 9.22.3 ## 1.1.2 - 2024-05-10 - - Integrated Boundary v2 functionality - +- ## 1.1.1 - 2023-11-15 - Added total count for household diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 798eba22c92..955934b5e1a 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -5,7 +5,7 @@ household jar household - 1.1.4 + 1.1.3 17 ${java.version} diff --git a/health-services/individual/CHANGELOG.md b/health-services/individual/CHANGELOG.md index 2ac982c765d..26df13994d2 100644 --- a/health-services/individual/CHANGELOG.md +++ b/health-services/individual/CHANGELOG.md @@ -1,11 +1,7 @@ All notable changes to this module will be documented in this file. -## 1.1.6 - 2024-08-29 - - - Added `ExistentEntityValidator` fixes - -## 1.1.5 - 2024-05-29 +## 1.1.5 - 2024-05-29 - Integrated Core 2.9LTS - Client reference ID validation added - Upgraded to health models 1.0.20 and health common 1.0.16 @@ -28,6 +24,8 @@ All notable changes to this module will be documented in this file. - Added proximity based search support +## 1.1.0 + ## 1.0.0 diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index d99c514e51b..392df06c2e1 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -5,7 +5,7 @@ individual jar individual - 1.1.6 + 1.1.5 17 ${java.version} diff --git a/health-services/libraries/health-services-common/pom.xml b/health-services/libraries/health-services-common/pom.xml index 5bdd15176c3..17c27125802 100644 --- a/health-services/libraries/health-services-common/pom.xml +++ b/health-services/libraries/health-services-common/pom.xml @@ -8,7 +8,7 @@ health-services-common jar health-services-common - 1.0.20-SNAPSHOT + 1.0.19-SNAPSHOT Shared classes among services @@ -115,13 +115,7 @@ org.egov.common health-services-models - 1.0.23-dev-SNAPSHOT - compile - - - org.egov - mdms-client - 2.9.0-SNAPSHOT + 1.0.22-SNAPSHOT compile diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java index 269a15e449d..537a82400cc 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java @@ -4,7 +4,6 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; -import org.egov.common.models.core.SearchResponse; import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; @@ -24,7 +23,6 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; @@ -238,52 +236,6 @@ public void putInCache(List objects, String key) { cacheByKey(objects, key); } - /** - * Finds entities based on search criteria, also returns the count of entities found. - * - * @param searchObject The object containing search criteria. - * @param limit The maximum number of entities to return. - * @param offset The offset for pagination. - * @param tenantId The tenant ID to filter entities. - * @param lastChangedSince The timestamp for last modified entities. - * @param includeDeleted Flag to include deleted entities in the search result. - * @return A list of entities found based on the search criteria with total count. - * @throws QueryBuilderException If an error occurs while building the query. - */ - public SearchResponse findWithCount(Object searchObject, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws QueryBuilderException { - String query = selectQueryBuilder.build(searchObject, tableName); - query += " AND tenantId=:tenantId "; - if (query.contains(tableName + " AND")) { - query = query.replace(tableName + " AND", tableName + " WHERE"); - } - if (Boolean.FALSE.equals(includeDeleted)) { - query += "AND isDeleted=:isDeleted "; - } - if (lastChangedSince != null) { - query += "AND lastModifiedTime>=:lastModifiedTime "; - } - query += "ORDER BY id ASC"; - Map paramsMap = selectQueryBuilder.getParamsMap(); - paramsMap.put("tenantId", tenantId); - paramsMap.put("isDeleted", includeDeleted); - paramsMap.put("lastModifiedTime", lastChangedSince); - - Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, namedParameterJdbcTemplate); - - query += " LIMIT :limit OFFSET :offset"; - paramsMap.put("limit", limit); - paramsMap.put("offset", offset); - - List resultantList = namedParameterJdbcTemplate.query(query, paramsMap, rowMapper); - - return SearchResponse.builder().response(resultantList).totalCount(totalCount).build(); - } - /** * Finds entities based on search criteria. * diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index dc4e4c878ca..cae31ed2480 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.egov.common health-services-models - 1.0.23-SNAPSHOT + 1.0.22-SNAPSHOT 17 ${java.version} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java index e1550174657..4209e6e2311 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java @@ -14,42 +14,27 @@ import org.springframework.validation.annotation.Validated; /** - * Represents a bulk response for facilities, including response metadata and a list of facilities. + * FacilityResponse */ @Validated + + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class FacilityBulkResponse { - - /** - * Metadata about the API response, including request details and status. - */ @JsonProperty("ResponseInfo") @NotNull @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; - /** - * List of facilities returned in the response. - */ @JsonProperty("Facilities") @Valid private List facilities = null; - /** - * Total number of facilities in the response, defaults to 0. - */ - @JsonProperty("TotalCount") - @Valid - @Builder.Default - private Long totalCount = 0L; - /** - * Adds a single facility to the list and returns the updated response. - */ public FacilityBulkResponse addFacilityItem(Facility facilityItem) { if (this.facilities == null) { this.facilities = new ArrayList<>(); @@ -57,4 +42,6 @@ public FacilityBulkResponse addFacilityItem(Facility facilityItem) { this.facilities.add(facilityItem); return this; } + } + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java index 60647504677..6ed081c182e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java @@ -15,10 +15,11 @@ import org.springframework.validation.annotation.Validated; /** - * IndividualBulkResponse represents the response structure for bulk operations related to individuals. - * It encapsulates the response information, total count of individuals, and a list of individual objects. + * IndividualResponse */ @Validated + + @Data @NoArgsConstructor @AllArgsConstructor @@ -26,35 +27,20 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class IndividualBulkResponse { - /** - * Metadata about the API response, including details like request status and other information. - */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; - /** - * Total count of individual records in the response, defaults to 0 if not specified. - */ @JsonProperty("TotalCount") @Valid @Builder.Default private Long totalCount = 0L; - - /** - * List of individual records returned in the response. - */ + @JsonProperty("Individual") @Valid private List individual = null; - /** - * Adds a single individual record to the list and returns the updated response. - * - * @param individualItem The individual record to add to the list. - * @return The updated IndividualBulkResponse instance. - */ public IndividualBulkResponse addIndividualItem(Individual individualItem) { if (this.individual == null) { this.individual = new ArrayList<>(); @@ -62,4 +48,6 @@ public IndividualBulkResponse addIndividualItem(Individual individualItem) { this.individual.add(individualItem); return this; } + } + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java index 38d1df9eafa..3b7c899ebfe 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java @@ -15,46 +15,29 @@ import org.springframework.validation.annotation.Validated; /** - * Represents a bulk response for project facilities, including response metadata and a list of facilities. + * ProjectFacilityResponse */ @Validated + + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class ProjectFacilityBulkResponse { - - /** - * Metadata about the API response, including request details and status. - */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; - /** - * Total number of project facilities in the response, defaults to 0. - */ - @JsonProperty("TotalCount") - @Valid - @Builder.Default - private Long totalCount = 0L; - - /** - * List of project facilities returned in the response. - */ @JsonProperty("ProjectFacilities") @NotNull @Valid private List projectFacilities = new ArrayList<>(); - /** - * Adds a single project facility to the list and returns the updated response. - */ public ProjectFacilityBulkResponse addProjectFacilityItem(ProjectFacility projectFacilityItem) { this.projectFacilities.add(projectFacilityItem); return this; } } - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java index 7aef41e322b..2fdba28281a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java @@ -37,11 +37,6 @@ public class ProjectResourceBulkResponse { @Valid private List projectResource = new ArrayList<>(); - @JsonProperty("TotalCount") - @Valid - @Builder.Default - private Long totalCount = 0L; - public ProjectResourceBulkResponse addProjectResourceItem(ProjectResource projectResourceItem) { this.projectResource.add(projectResourceItem); return this; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java index 49070e25a94..73d80462fb0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java @@ -15,9 +15,11 @@ import org.springframework.validation.annotation.Validated; /** - * Represents a bulk response for project staff, containing response metadata and a list of staff members. - */ +* ProjectStaffResponse +*/ @Validated + + @Data @NoArgsConstructor @AllArgsConstructor @@ -25,38 +27,19 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class ProjectStaffBulkResponse { - /** - * Metadata about the API response, including request status and other information. - */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; - /** - * List of project staff members returned in the response. - */ @JsonProperty("ProjectStaff") @NotNull @Valid private List projectStaff = new ArrayList<>(); - /** - * Total number of project staff members in the response, defaults to 0 if not specified. - */ - @JsonProperty("TotalCount") - @Valid - @Builder.Default - private Long totalCount = 0L; - - /** - * Adds a single project staff member to the list and returns the updated response. - * - * @param projectStaffItem The project staff member to add to the list. - * @return The updated ProjectStaffBulkResponse instance. - */ public ProjectStaffBulkResponse addProjectStaffItem(ProjectStaff projectStaffItem) { this.projectStaff.add(projectStaffItem); return this; } } + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java index 0e2051b6be6..4c6ad63a53f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java @@ -1,7 +1,5 @@ package org.egov.common.models.project.useraction; -import java.util.List; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java index d8791d66979..a561ef4f8a4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java @@ -13,39 +13,21 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.response.ResponseInfo; -/** - * Represents a bulk response for HF (Health Facility) referrals, containing response metadata and a list of referrals. - */ @Data @NoArgsConstructor @AllArgsConstructor @Builder public class HFReferralBulkResponse { - - /** - * Metadata about the API response, including details such as request status and information. - */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo; - /** - * List of health facility referrals returned in the response. - */ @JsonProperty("HFReferrals") @NotNull @Valid private List hfReferrals; - /** - * Total number of HF referrals in the response, defaults to 0 if not specified. - */ - @JsonProperty("TotalCount") - @Valid - @Builder.Default - private Long totalCount = 0L; - /** * Add a HfReferral item to the list of HfReferrals in the bulk response. * diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java index 3ad45bc8ed7..3f52835a270 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java @@ -14,9 +14,11 @@ import org.springframework.validation.annotation.Validated; /** - * Represents a bulk response for stock items, containing response metadata and a list of stock entries. + * StockResponse */ @Validated + + @Data @NoArgsConstructor @AllArgsConstructor @@ -24,40 +26,20 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class StockBulkResponse { - /** - * Metadata about the API response, including details such as request status and information. - */ @JsonProperty("ResponseInfo") @NotNull @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; - /** - * List of stock items returned in the response. - */ @JsonProperty("Stock") @NotNull @Valid private List stock = new ArrayList<>(); - /** - * Total number of stock items in the response, defaults to 0 if not specified. - */ - @JsonProperty("TotalCount") - @Valid - @Builder.Default - private Long totalCount = 0L; - - /** - * Adds a single stock item to the list of stock and returns the updated response. - * - * @param stockItem The stock item to add to the list. - * @return The updated StockBulkResponse instance. - */ + public StockBulkResponse addStockItem(Stock stockItem) { this.stock.add(stockItem); return this; } } - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java index bae326d2dd8..17ea81e8ed7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java @@ -14,9 +14,11 @@ import org.springframework.validation.annotation.Validated; /** - * Represents a bulk response for stock reconciliation, containing response metadata and a list of stock reconciliation entries. + * StockReconciliationResponse */ @Validated + + @Data @NoArgsConstructor @AllArgsConstructor @@ -24,38 +26,19 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class StockReconciliationBulkResponse { - /** - * Metadata about the API response, including details such as request status and information. - */ @JsonProperty("ResponseInfo") @NotNull @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; - /** - * List of stock reconciliation items returned in the response. - */ @JsonProperty("StockReconciliation") @NotNull @Valid private List stockReconciliation = new ArrayList<>(); - /** - * Total number of stock reconciliation items in the response, defaults to 0 if not specified. - */ - @JsonProperty("TotalCount") - @Valid - @Builder.Default - private Long totalCount = 0L; - - /** - * Adds a single stock reconciliation item to the list and returns the updated response. - * - * @param stockReconciliationItem The stock reconciliation item to add to the list. - * @return The updated StockReconciliationBulkResponse instance. - */ public StockReconciliationBulkResponse addStockReconciliationItem(StockReconciliation stockReconciliationItem) { this.stockReconciliation.add(stockReconciliationItem); return this; } } + diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java index 4645ce10b5e..f289c5d4818 100644 --- a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java @@ -12,7 +12,10 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; @Component public class PlanConfigRowMapper implements ResultSetExtractor> { @@ -26,10 +29,10 @@ public PlanConfigRowMapper(QueryUtil queryUtil) { @Override public List extractData(ResultSet rs) throws SQLException, DataAccessException { Map planConfigurationMap = new LinkedHashMap<>(); - Set fileSet = new HashSet<>(); - Set operationSet = new HashSet<>(); - Set assumptionSet = new HashSet<>(); - Set resourceMappingSet = new HashSet<>(); + Map fileMap = new LinkedHashMap<>(); + Map operationMap = new LinkedHashMap<>(); + Map assumptionMap = new LinkedHashMap<>(); + Map resourceMappingMap = new LinkedHashMap<>(); while (rs.next()) { @@ -39,10 +42,6 @@ public List extractData(ResultSet rs) throws SQLException, Da if (ObjectUtils.isEmpty(planConfigEntry)) { planConfigEntry = new PlanConfiguration(); - fileSet.clear(); - operationSet.clear(); - assumptionSet.clear(); - resourceMappingSet.clear(); // Prepare audit details AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("plan_configuration_created_by")).createdTime(rs.getLong("plan_configuration_created_time")).lastModifiedBy(rs.getString("plan_configuration_last_modified_by")).lastModifiedTime(rs.getLong("plan_configuration_last_modified_time")).build(); @@ -57,10 +56,10 @@ public List extractData(ResultSet rs) throws SQLException, Da planConfigEntry.setAuditDetails(auditDetails); } - addFiles(rs, planConfigEntry, fileSet); - addAssumptions(rs, planConfigEntry, assumptionSet); - addOperations(rs, planConfigEntry, operationSet); - addResourceMappings(rs, planConfigEntry, resourceMappingSet); + addFiles(rs, planConfigEntry, fileMap); + addAssumptions(rs, planConfigEntry, assumptionMap); + addOperations(rs, planConfigEntry, operationMap); + addResourceMappings(rs, planConfigEntry, resourceMappingMap); planConfigurationMap.put(planConfigId, planConfigEntry); } @@ -72,13 +71,13 @@ public List extractData(ResultSet rs) throws SQLException, Da * * @param rs The ResultSet containing the data. * @param planConfigEntry The PlanConfiguration entry to which the File object will be added. - * @param fileSet A set to keep track of added File objects. + * @param fileMap A map to keep track of added File objects. * @throws SQLException If an SQL error occurs. */ - private void addFiles(ResultSet rs, PlanConfiguration planConfigEntry, Set fileSet) throws SQLException { + private void addFiles(ResultSet rs, PlanConfiguration planConfigEntry, Map fileMap) throws SQLException { String fileId = rs.getString("plan_configuration_files_id"); - if (ObjectUtils.isEmpty(fileId) || fileSet.contains(fileId)) { + if (ObjectUtils.isEmpty(fileId) || fileMap.containsKey(fileId)) { return; } @@ -96,7 +95,7 @@ private void addFiles(ResultSet rs, PlanConfiguration planConfigEntry, Set assumptionSet) throws SQLException { + private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Map assumptionMap) throws SQLException { String assumptionId = rs.getString("plan_configuration_assumptions_id"); - if (ObjectUtils.isEmpty(assumptionId) || assumptionSet.contains(assumptionId)) { + if (ObjectUtils.isEmpty(assumptionId) || assumptionMap.containsKey(assumptionId)) { return; } @@ -131,7 +130,7 @@ private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Set planConfigEntry.getAssumptions().add(assumption); } - assumptionSet.add(assumptionId); + assumptionMap.put(assumptionId, assumption); } /** @@ -139,13 +138,13 @@ private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Set * * @param rs The ResultSet containing the data. * @param planConfigEntry The PlanConfiguration entry to which the Operation object will be added. - * @param operationSet A set to keep track of added Operation objects. + * @param operationMap A map to keep track of added Operation objects. * @throws SQLException If an SQL error occurs. */ - private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Set operationSet) throws SQLException { + private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Map operationMap) throws SQLException { String operationId = rs.getString("plan_configuration_operations_id"); - if (ObjectUtils.isEmpty(operationId) || operationSet.contains(operationId)) { + if (ObjectUtils.isEmpty(operationId) || operationMap.containsKey(operationId)) { return; } @@ -169,7 +168,7 @@ private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Set< planConfigEntry.getOperations().add(operation); } - operationSet.add(operationId); + operationMap.put(operationId, operation); } /** @@ -177,13 +176,13 @@ private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Set< * * @param rs The ResultSet containing the data. * @param planConfigEntry The PlanConfiguration entry to which the ResourceMapping object will be added. - * @param resourceMappingSet A set to keep track of added ResourceMapping objects. + * @param mappingMap A map to keep track of added ResourceMapping objects. * @throws SQLException If an SQL error occurs. */ - private void addResourceMappings(ResultSet rs, PlanConfiguration planConfigEntry, Set resourceMappingSet) throws SQLException { + private void addResourceMappings(ResultSet rs, PlanConfiguration planConfigEntry, Map mappingMap) throws SQLException { String mappingId = rs.getString("plan_configuration_mapping_id"); - if (ObjectUtils.isEmpty(mappingId) || resourceMappingSet.contains(mappingId)) { + if (ObjectUtils.isEmpty(mappingId) || mappingMap.containsKey(mappingId)) { return; } @@ -202,7 +201,7 @@ private void addResourceMappings(ResultSet rs, PlanConfiguration planConfigEntry planConfigEntry.getResourceMapping().add(mapping); } - resourceMappingSet.add(mappingId); + mappingMap.put(mappingId, mapping); } } diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java index aa00207a741..4ba29529384 100644 --- a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java @@ -27,9 +27,9 @@ public PlanRowMapper(QueryUtil queryUtil) { public List extractData(ResultSet rs) throws SQLException, DataAccessException { Map planMap = new LinkedHashMap<>(); Map activityMap = new LinkedHashMap<>(); - Set conditionSet = new HashSet<>(); - Set resourceSet = new HashSet<>(); - Set targetSet = new HashSet<>(); + Map conditionMap = new LinkedHashMap<>(); + Map resourceMap = new LinkedHashMap<>(); + Map targetMap = new LinkedHashMap<>(); // Traverse through result set and create plan objects while (rs.next()) { @@ -39,10 +39,6 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExcep if (ObjectUtils.isEmpty(planEntry)) { planEntry = new Plan(); - activityMap.clear(); - conditionSet.clear(); - resourceSet.clear(); - targetSet.clear(); // Prepare audit details AuditDetails auditDetails = AuditDetails.builder() @@ -69,9 +65,9 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExcep } - addActivities(rs, planEntry, activityMap, conditionSet); - addResources(rs, planEntry, resourceSet); - addTargets(rs, planEntry, targetSet); + addActivities(rs, planEntry, activityMap, conditionMap); + addResources(rs, planEntry, resourceMap); + addTargets(rs, planEntry, targetMap); planMap.put(planId, planEntry); } @@ -79,12 +75,12 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExcep } private void addActivities(ResultSet rs, Plan plan, - Map activityMap, Set conditionSet) throws SQLException, DataAccessException { + Map activityMap, Map conditionMap) throws SQLException, DataAccessException { String activityId = rs.getString("plan_activity_id"); if (!ObjectUtils.isEmpty(activityId) && activityMap.containsKey(activityId)) { - addActivityConditions(rs, activityMap.get(activityId), conditionSet); + addActivityConditions(rs, activityMap.get(activityId), conditionMap); return; } else if (ObjectUtils.isEmpty(activityId)) { // Set activities list to empty if no activity found @@ -109,7 +105,7 @@ private void addActivities(ResultSet rs, Plan plan, .dependencies(ObjectUtils.isEmpty(dependencies) ? new ArrayList<>() : Arrays.asList(rs.getString("plan_activity_dependencies").split(","))) .build(); - addActivityConditions(rs, activity, conditionSet); + addActivityConditions(rs, activity, conditionMap); if (CollectionUtils.isEmpty(plan.getActivities())) { List activityList = new ArrayList<>(); @@ -123,10 +119,10 @@ private void addActivities(ResultSet rs, Plan plan, } - private void addActivityConditions(ResultSet rs, Activity activity, Set conditionSet) throws SQLException, DataAccessException { + private void addActivityConditions(ResultSet rs, Activity activity, Map conditionMap) throws SQLException, DataAccessException { String conditionId = rs.getString("plan_activity_condition_id"); - if (ObjectUtils.isEmpty(conditionId) || conditionSet.contains(conditionId)) { + if (ObjectUtils.isEmpty(conditionId) || conditionMap.containsKey(conditionId)) { List conditionList = new ArrayList<>(); activity.setConditions(conditionList); return; @@ -154,15 +150,15 @@ private void addActivityConditions(ResultSet rs, Activity activity, Set activity.getConditions().add(condition); } - conditionSet.add(condition.getId()); + conditionMap.put(condition.getId(), condition); } - private void addResources(ResultSet rs, Plan planEntry, Set resourceSet) throws SQLException, DataAccessException { + private void addResources(ResultSet rs, Plan planEntry, Map resourceMap) throws SQLException, DataAccessException { String resourceId = rs.getString("plan_resource_id"); - if (ObjectUtils.isEmpty(resourceId) || resourceSet.contains(resourceId)) { + if (ObjectUtils.isEmpty(resourceId) || resourceMap.containsKey(resourceId)) { List resourceList = new ArrayList<>(); planEntry.setResources(resourceList); return; @@ -190,14 +186,14 @@ private void addResources(ResultSet rs, Plan planEntry, Set resourceSet) planEntry.getResources().add(resource); } - resourceSet.add(resource.getId()); + resourceMap.put(resource.getId(), resource); } - private void addTargets(ResultSet rs, Plan planEntry, Set targetSet) throws SQLException, DataAccessException { + private void addTargets(ResultSet rs, Plan planEntry, Map targetMap) throws SQLException, DataAccessException { String targetId = rs.getString("plan_target_id"); - if (ObjectUtils.isEmpty(targetId) || targetSet.contains(targetId)) { + if (ObjectUtils.isEmpty(targetId) || targetMap.containsKey(targetId)) { List targetList = new ArrayList<>(); planEntry.setTargets(targetList); return; @@ -231,7 +227,7 @@ private void addTargets(ResultSet rs, Plan planEntry, Set targetSet) thr planEntry.getTargets().add(target); } - targetSet.add(target.getId()); + targetMap.put(target.getId(), target); } } diff --git a/health-services/plan-service/src/main/java/digit/service/enrichment/PlanEnricher.java b/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java similarity index 99% rename from health-services/plan-service/src/main/java/digit/service/enrichment/PlanEnricher.java rename to health-services/plan-service/src/main/java/digit/service/PlanEnricher.java index 17364bfdb6d..b01c78ea82a 100644 --- a/health-services/plan-service/src/main/java/digit/service/enrichment/PlanEnricher.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java @@ -1,4 +1,4 @@ -package digit.service.enrichment; +package digit.service; import digit.web.models.Plan; import digit.web.models.PlanRequest; diff --git a/health-services/plan-service/src/main/java/digit/service/PlanService.java b/health-services/plan-service/src/main/java/digit/service/PlanService.java index dad7e8b7d83..4acaf58218b 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanService.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanService.java @@ -1,13 +1,13 @@ package digit.service; import digit.repository.PlanRepository; -import digit.service.enrichment.PlanEnricher; -import digit.service.validator.PlanValidator; import digit.service.workflow.WorkflowService; import digit.web.models.*; +import org.egov.common.contract.response.ResponseInfo; import org.egov.common.utils.ResponseInfoUtil; import org.springframework.stereotype.Service; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; diff --git a/health-services/plan-service/src/main/java/digit/service/validator/PlanValidator.java b/health-services/plan-service/src/main/java/digit/service/PlanValidator.java similarity index 99% rename from health-services/plan-service/src/main/java/digit/service/validator/PlanValidator.java rename to health-services/plan-service/src/main/java/digit/service/PlanValidator.java index 1fd98c823b7..8f495a271f8 100644 --- a/health-services/plan-service/src/main/java/digit/service/validator/PlanValidator.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanValidator.java @@ -1,11 +1,9 @@ -package digit.service.validator; +package digit.service; import com.jayway.jsonpath.JsonPath; import digit.config.Configuration; import digit.repository.PlanConfigurationRepository; import digit.repository.PlanRepository; -import digit.service.PlanEmployeeService; -import digit.service.enrichment.PlanEnricher; import digit.util.BoundaryUtil; import digit.util.CampaignUtil; import digit.util.CommonUtil; @@ -546,12 +544,15 @@ private void validateBoundaryCode(BoundarySearchResponse boundarySearchResponse, throw new CustomException(NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE, NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE); } + //TODO: change to if(!plan.isRequestFromResourceEstimationConsumer()) after triggering from consumer + // Enrich the boundary ancestral path and jurisdiction mapping for the provided boundary code if(plan.isRequestFromResourceEstimationConsumer()) planEnricher.enrichBoundaryAncestralPath(plan, tenantBoundary); } /** + * TODO - 1. plan existence 2. plan employee assignment 3. uniqueness check across records * @param bulkPlanRequest */ public void validateBulkPlanUpdate(BulkPlanRequest bulkPlanRequest) { @@ -673,4 +674,4 @@ private void enrichAncestralMaterializedPath(BulkPlanRequest bulkPlanRequest, Li .get(plan.getId())) ); } -} \ No newline at end of file +} diff --git a/health-services/project-factory/CHANGELOG.md b/health-services/project-factory/CHANGELOG.md index 47034044d78..55f990d91ba 100644 --- a/health-services/project-factory/CHANGELOG.md +++ b/health-services/project-factory/CHANGELOG.md @@ -8,15 +8,3 @@ All notable changes to this module will be documented in this file. 3. Create Data: Validates and creates resource details of type facility,user and boundary. 4. Generate Data: Generates sheet data of type facility,user and boundary. 5. Boundary and Resource Validation: Validates boundaries and resources during campaign creation and updating. - -## 0.2.0 - 2024-08-7 -#### ProjectFactory service version 0.2 - 1. Timeline integration for workflow of campaign. - 2. Call user, facility and boundary generate when boundaries changed in campaign update flow - 3. Generate target template based on delivery conditions changed to anything from default. - -## 0.3.0 - 2024-12-03 - 1. Campaign Details Table Updates -> added new columns: parentId and active,removed unique constraint on campaignName. - 2. Update Ongoing Campaign (can add new boundaries , edit facilities , user and target sheet). - 3. Boundary Management Apis added. - 4. Microplan Integration api (fetch-from-microplan api) added. diff --git a/health-services/project-factory/Dockerfile b/health-services/project-factory/Dockerfile index 4b942010773..124ed02c197 100644 --- a/health-services/project-factory/Dockerfile +++ b/health-services/project-factory/Dockerfile @@ -13,7 +13,6 @@ ARG COMMIT_ID ENV BRANCH_NAME=$BRANCH_NAME ENV ACTION_NUMBER=$ACTION_NUMBER ENV COMMIT_ID=$COMMIT_ID -ENV NODE_OPTIONS="--max-old-space-size=2048" # Copy package.json and yarn.lock (if exists) COPY package.json ./ @@ -31,4 +30,5 @@ COPY . . EXPOSE 3000 CMD ["yarn", "prod"] -# Replaced by CMD ["yarn", "prod"] \ No newline at end of file + # Replace "app.js" with your entry point file + diff --git a/health-services/project-factory/README.md b/health-services/project-factory/README.md index 0b545626fe6..40aee6d33bc 100644 --- a/health-services/project-factory/README.md +++ b/health-services/project-factory/README.md @@ -1,93 +1,84 @@ -# ProjectFactory Service +# ProjectFactory-Service -The **ProjectFactory Service** is responsible for managing project-type campaigns, including creating, updating, searching, and generating campaign data. +The Project Factory Service is responsible for managing project-type campaigns, including creating, updating, searching, and creating campaigns. -## DB UML Diagram +### DB UML Diagram -![DB UML Diagram](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/8c43998d-742b-4629-ae90-63ab2b18772b) -![DB UML Diagram](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/3ff9609d-771a-4c6e-a769-54766e7111f7) +![image](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/8c43998d-742b-4629-ae90-63ab2b18772b) +![image](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/3ff9609d-771a-4c6e-a769-54766e7111f7) -## Service Dependencies -### Core Services +### Service Dependencies -- `egov-localization` -- `egov-filestore` -- `egov-persister` -- `egov-mdms` -- `egov-idgen` -- `egov-boundaryservice-v2` +#### Core services -### Health Services +- egov-localization +- egov-filestore +- egov-persister +- egov-mdms +- egov-idgen +- egov-boundaryservice-v2 -- `health-project` -- `health-hrms` -- `health-facility` +#### Health services +- health-project +- health-hrms +- health-facility -### Caching +### Swagger API Contract +Please refer to the below Swagger API contract, for ProjectFactory service to understand the structure of APIs and to have visualization of all internal APIs [Swagger API contract](https://editor.swagger.io/?url=https://raw.githubusercontent.com/jagankumar-egov/DIGIT-Specs/hcm-workbench/Domain%20Services/Health/project-factory.yaml) -- `Redis` is now used to store cache for frequently accessed data to improve performance. - -## Swagger API Contract - -For the structure and visualization of APIs, refer to the [Swagger API contract](https://editor.swagger.io/?url=https://raw.githubusercontent.com/jagankumar-egov/DIGIT-Specs/hcm-workbench/Domain%20Services/Health/project-factory.yaml). ## Service Details -### Functionality - -1. **Campaign Management**: Manages project-type campaigns, including creation, updating, searching, and data generation. -2. **Project Mapping**: Completes full project mapping with staff, facility, and resources along with proper target values during campaign creation. -3. **Data Creation**: Validates and creates resource details of types `facility`, `user`, and `boundary`. -4. **Data Generation**: Generates sheet data of types `facility`, `user`, and `boundary`. -5. **Validation**: Validates boundaries and resources during campaign creation and updating. - -### Features - -1. **Easy Campaign Creation**: Facilitates easy creation of campaigns. -2. **File Storage**: Uploads generated data sheets to `egov-filestore` and returns the file store ID for easy access. -3. **Localization Support**: Supports localization for multi-language adaptability. -4. **Customizable Delivery Rules**: Allows defining delivery rules for projects based on specific criteria. -5. **Search and Filtering**: Enables searching and filtering campaigns based on parameters like status, date, and creator. -6. **Batch Processing**: Supports batch processing for creating and updating multiple campaigns simultaneously. -7. **Caching with Redis**: Improves performance by caching frequently accessed data. +### Funcatinality +1. ProjectFactory Service manages campaigns: creation, updating, searching, and data generation. +2. Project Mapping : In campaign creation full project mapping is done with staff, facility and resources along with proper target values. +3. Create Data: Validates and creates resource details of type facility,user and boundary. +4. Generate Data: Generates sheet data of type facility,user and boundary. +5. Boundary and Resource Validation: Validates boundaries and resources during campaign creation and updating. + +### Feature +1. Functionality to create campaigns easily. +2. Uploading generated datas sheets to filestore and return filestore id for easy access. +3. Supports localisation. +4. Customizable Delivery Rules: Allows defining delivery rules for projects based on specific criteria. +5. Search and Filtering: Enables searching and filtering campaigns based on various parameters like status, date, and creator. +6. Batch Processing: Supports batch processing for creating and updating multiple campaigns simultaneously. ### External Libraries Used +[xlsx](https://github.com/SheetJS/sheetjs):- For reading and writing Excel files. -- **[xlsx](https://github.com/SheetJS/sheetjs)**: For reading and writing Excel files. -- **[ajv](https://github.com/ajv-validator/ajv)**: For JSON schema validation. -- **[lodash](https://github.com/lodash/lodash)**: For utility functions like data manipulation and object iteration. +[ajv](https://github.com/ajv-validator/ajv):- For JSON schema validation. -## Configuration +[lodash](https://github.com/lodash/lodash):- For utility functions like data manipulation and object iteration. -- **Persister Config**: [Link](https://github.com/egovernments/configs/blob/UNIFIED-UAT/health/egov-persister/project-factory-persister.yml) -- **Helm Chart Details**: [Link](https://github.com/egovernments/DIGIT-DevOps/blob/unified-env/deploy-as-code/helm/charts/health-services/project-factory/values.yaml) -## API Endpoints +### Configuration -- **`POST /project-factory/v1/project-type/create`**: Creates a new project-type campaign. -- **`PUT /project-factory/v1/project-type/update`**: Updates an existing project-type campaign. -- **`POST /project-factory/v1/project-type/search`**: Searches for project-type campaigns based on specified criteria. -- **`POST /project-factory/v1/data/_create`**: Creates or validates resource data (e.g., facility, user, boundary). -- **`POST /project-factory/v1/data/_search`**: Searches for resource data based on specified criteria. -- **`POST /project-factory/v1/data/_generate`**: Initiates the generation of new data based on provided parameters. -- **`GET /project-factory/v1/data/_download`**: Downloads resource data based on specified criteria. +- Persister config: [here](https://github.com/egovernments/configs/blob/UNIFIED-UAT/health/egov-persister/project-factory-persister.yml) +- Helm chart details: [here](https://github.com/egovernments/DIGIT-DevOps/blob/unified-env/deploy-as-code/helm/charts/health-services/project-factory/values.yaml) + +### API Endpoints -## Kafka Consumers +- `/project-factory/v1/project-type/create`: Creates a new project type campaign. +- `/project-factory/v1/project-type/update`: Updates an existing project type campaign. +- `/project-factory/v1/project-type/search`: Searches for project type campaigns based on specified criteria. +- `/project-factory/v1/data/_create`: Creates or validates resource data (e.g., facility, user, boundary). +- `/project-factory/v1/data/_search`: Searches for resource data based on specified criteria. +- `/project-factory/v1/data/_generate`: Initiates the generation of new data based on provided parameters. +- `/project-factory/v1/data/_download`: Downloads resource data based on specified criteria. -- **`start-campaign-mapping`**: Initiates the mapping process for campaigns. -## Kafka Producers +### Kafka Consumers -- **`save-project-campaign-details`**: Saves project campaign details after creation. -- **`update-project-campaign-details`**: Updates project campaign details. -- **`create-resource-details`**: Creates resource details. -- **`update-resource-details`**: Updates resource details. -- **`create-resource-activity`**: Creates resource activity. -- **`create-generated-resource-details`**: Saves details for generated resources. -- **`update-generated-resource-details`**: Updates details for generated resources. +- start-campaign-mapping: This topic is used by the service to initiate the mapping process for campaigns. -## Redis Caching +### Kafka Producers -- **Purpose**: Enhances performance by caching frequently accessed data and reducing the load on the database. -- **Usage**: Commonly used to store temporary data like search results, and other frequently accessed resources. +- save-project-campaign-details: This topic is used to save project campaign details after creation. +- update-project-campaign-details: This topic is used to update project campaign details. +- create-resource-details: This topic is used to create resource details. +- update-resource-details: This topic is used to update resource details. +- create-resource-activity: This topic is used to create resource activity creation. +- create-generated-resource-details: This topic is used to save details for generated resources. +- update-generated-resource-details: This topic is used to update details for generated resources. diff --git a/health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql b/health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql new file mode 100644 index 00000000000..aecfae20001 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql @@ -0,0 +1,46 @@ +CREATE TABLE eg_cm_resource_details ( + id varchar(128) PRIMARY KEY, + "status" varchar(128) NOT NULL, + tenantId varchar(128) NOT NULL, + fileStoreId varchar(128) NOT NULL, + processedFileStoreId varchar(128), + "action" varchar(128) NOT NULL, + "type" varchar(64) NOT NULL, + createdBy varchar(128) NOT NULL, + createdTime bigint NOT NULL, + lastModifiedBy varchar(128), + lastModifiedTime bigint, + additionalDetails jsonb +); + +CREATE TABLE eg_cm_resource_activity ( + id varchar(128) PRIMARY KEY, + retryCount integer, + "type" varchar(64), + "url" varchar(128), + requestPayload jsonb, + tenantId varchar(128) NOT NULL, + responsePayload jsonb, + "status" bigint, + createdBy varchar(128), + createdTime bigint, + lastModifiedBy varchar(128), + lastModifiedTime bigint, + additionalDetails jsonb, + resourceDetailsId varchar(128), + FOREIGN KEY (resourceDetailsId) REFERENCES eg_cm_resource_details(id) +); + +CREATE TABLE eg_cm_generated_resource_details ( + id varchar(128) PRIMARY KEY, + fileStoreId varchar(128), + "status" varchar(128), + "type" varchar(128), + tenantid varchar(128), + count bigint, + createdBy varchar(128), + createdTime bigint, + lastModifiedBy varchar(128), + lastModifiedTime bigint, + additionalDetails jsonb +); diff --git a/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql b/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql new file mode 100644 index 00000000000..1f6426149f5 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql @@ -0,0 +1,16 @@ +CREATE TABLE eg_cm_campaign_details ( + id character varying(128) PRIMARY KEY, + tenantId character varying(64) NOT NULL, + "status" character varying(128) NOT NULL, + "action" character varying(64) NOT NULL, + campaignNumber character varying(128) NOT NULL, + hierarchyType character varying(128) NOT NULL, + boundaryCode character varying(64), + projectId character varying(128), + createdBy character varying(128) NOT NULL, + lastModifiedBy character varying(128), + createdTime bigint NOT NULL, + lastModifiedTime bigint, + additionalDetails jsonb, + campaignDetails jsonb +); diff --git a/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql b/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql new file mode 100644 index 00000000000..eaf0c681333 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql @@ -0,0 +1,3 @@ +ALTER TABLE eg_cm_campaign_details +ADD COLUMN campaignName character varying(128) UNIQUE, +ADD COLUMN projectType character varying(128); diff --git a/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql b/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql new file mode 100644 index 00000000000..7a49127c9dd --- /dev/null +++ b/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_campaign_details +ALTER COLUMN hierarchyType DROP NOT NULL; diff --git a/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql b/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql new file mode 100644 index 00000000000..05dfea2b5c7 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql @@ -0,0 +1,3 @@ +ALTER TABLE eg_cm_campaign_details +ADD COLUMN startDate bigint, +ADD COLUMN endDate bigint; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql b/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql new file mode 100644 index 00000000000..c96caaa0e5f --- /dev/null +++ b/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_generated_resource_details +ADD COLUMN hierarchyType varchar(128); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql b/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql new file mode 100644 index 00000000000..36707083732 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_campaign_details +ALTER COLUMN campaignName TYPE character varying(250); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql b/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql new file mode 100644 index 00000000000..25fc10438f1 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_resource_details +ADD COLUMN campaignId character varying(128); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240826145500__add_resource_and_campaign.sql b/health-services/project-factory/migration/main/V20240826145500__add_resource_and_campaign.sql deleted file mode 100644 index 09165a225d3..00000000000 --- a/health-services/project-factory/migration/main/V20240826145500__add_resource_and_campaign.sql +++ /dev/null @@ -1,92 +0,0 @@ -CREATE TABLE eg_cm_campaign_details -( - id character varying(128) NOT NULL, - tenantid character varying(64) NOT NULL, - status character varying(128) NOT NULL, - action character varying(64) NOT NULL, - campaignnumber character varying(128) NOT NULL, - hierarchytype character varying(128), - boundarycode character varying(64), - projectid character varying(128), - createdby character varying(128) NOT NULL, - lastmodifiedby character varying(128), - createdtime bigint NOT NULL, - lastmodifiedtime bigint, - additionaldetails jsonb, - campaigndetails jsonb, - campaignname character varying(250), - projecttype character varying(128), - startdate bigint, - enddate bigint, - CONSTRAINT eg_cm_campaign_details_pkey PRIMARY KEY (id), - CONSTRAINT eg_cm_campaign_details_campaignname_key UNIQUE (campaignname) -); - -CREATE TABLE eg_cm_campaign_process -( - id character varying(128) NOT NULL, - campaignid character varying(128) NOT NULL, - type character varying(128), - status character varying(128), - details jsonb, - createdtime bigint, - lastmodifiedtime bigint, - additionaldetails jsonb, - CONSTRAINT eg_cm_campaign_process_pkey PRIMARY KEY (id), - CONSTRAINT uq_campaignid_type UNIQUE (campaignid, type) -); - -CREATE TABLE eg_cm_generated_resource_details -( - id character varying(128) NOT NULL, - filestoreid character varying(128), - status character varying(128), - type character varying(128), - tenantid character varying(128), - count bigint, - createdby character varying(128), - createdtime bigint, - lastmodifiedby character varying(128), - lastmodifiedtime bigint, - additionaldetails jsonb, - hierarchytype character varying(128), - campaignid character varying(128), - CONSTRAINT eg_cm_generated_resource_details_pkey PRIMARY KEY (id) -); - -CREATE TABLE eg_cm_resource_activity -( - id character varying(128) NOT NULL, - retrycount integer, - type character varying(64), - url character varying(128), - requestpayload jsonb, - tenantid character varying(128) NOT NULL, - responsepayload jsonb, - status bigint, - createdby character varying(128), - createdtime bigint, - lastmodifiedby character varying(128), - lastmodifiedtime bigint, - additionaldetails jsonb, - resourcedetailsid character varying(128), - CONSTRAINT eg_cm_resource_activity_pkey PRIMARY KEY (id) -); - -CREATE TABLE eg_cm_resource_details -( - id character varying(128) NOT NULL, - status character varying(128) NOT NULL, - tenantid character varying(128) NOT NULL, - filestoreid character varying(128) NOT NULL, - processedfilestoreid character varying(128), - action character varying(128) NOT NULL, - type character varying(64) NOT NULL, - createdby character varying(128) NOT NULL, - createdtime bigint NOT NULL, - lastmodifiedby character varying(128), - lastmodifiedtime bigint, - additionaldetails jsonb, - campaignid character varying(128), - CONSTRAINT eg_cm_resource_details_pkey PRIMARY KEY (id) -); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql b/health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql deleted file mode 100644 index 59df89af11c..00000000000 --- a/health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE INDEX idx_eg_cm_campaign_details_status ON eg_cm_campaign_details(status); -CREATE INDEX idx_eg_cm_campaign_details_campaignname ON eg_cm_campaign_details(campaignname); -CREATE INDEX idx_eg_cm_campaign_process_campaignid ON eg_cm_campaign_process(campaignid); -CREATE INDEX idx_eg_cm_generated_resource_details_campaignid ON eg_cm_generated_resource_details(campaignid); -CREATE INDEX idx_eg_cm_resource_details_campaignid ON eg_cm_resource_details(campaignid); diff --git a/health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql b/health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql deleted file mode 100644 index 6ce6b0f771e..00000000000 --- a/health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE eg_cm_campaign_details -ADD COLUMN parentid character varying(128); - -ALTER TABLE eg_cm_campaign_details -ADD COLUMN isactive boolean; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql b/health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql deleted file mode 100644 index 34aa7b31978..00000000000 --- a/health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE eg_cm_campaign_details -DROP CONSTRAINT eg_cm_campaign_details_campaignname_key; diff --git a/health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql b/health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql deleted file mode 100644 index e44468f1cc5..00000000000 --- a/health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE eg_cm_resource_details ADD COLUMN hierarchytype character varying(128); \ No newline at end of file diff --git a/health-services/project-factory/migration/migrate.sh b/health-services/project-factory/migration/migrate.sh index c433c239956..5593a173eba 100755 --- a/health-services/project-factory/migration/migrate.sh +++ b/health-services/project-factory/migration/migrate.sh @@ -1,4 +1,3 @@ #!/bin/sh -flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS repair flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true migrate \ No newline at end of file diff --git a/health-services/project-factory/package-lock.json b/health-services/project-factory/package-lock.json index c13d8382b36..5d9d7df918a 100644 --- a/health-services/project-factory/package-lock.json +++ b/health-services/project-factory/package-lock.json @@ -1,24 +1,23 @@ { "name": "project-factory", - "version": "0.2.0", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "project-factory", - "version": "0.2.0", + "version": "0.0.1", "license": "MIT", "dependencies": { "ajv-errors": "^3.0.0", "axios": "1.6.8", "body-parser": "^1.20.2", "compression": "1.7.4", - "exceljs": "^4.4.0", + "exceljs": "4.4.0", "express": "^4.19.2", "hash-sum": "2.0.0", "helmet": "7.1.0", "http-proxy-middleware": "^3.0.0", - "ioredis": "^5.4.1", "jaeger-client": "^3.19.0", "jsonpath": "1.1.1", "kafka-node": "5.0.0", @@ -41,7 +40,6 @@ "@types/http-proxy-middleware": "^1.0.0", "@types/jaeger-client": "^3.18.7", "@types/jest": "29.5.12", - "@types/lodash": "^4.17.5", "@types/morgan": "1.9.9", "@types/node": "20.11.29", "@types/pg": "8.11.3", @@ -55,11 +53,22 @@ "typescript": "5.4.2" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -69,43 +78,38 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" + "@babel/highlight": "^7.10.4" } }, "node_modules/@babel/compat-data": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", - "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", + "version": "7.24.4", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", - "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "version": "7.24.4", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-module-transforms": "^7.25.2", - "@babel/helpers": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.2", - "@babel/types": "^7.25.2", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -120,11 +124,26 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/core/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -141,24 +160,25 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", - "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "version": "7.24.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.25.0", + "@babel/types": "^7.24.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -168,14 +188,15 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -183,53 +204,78 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", - "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.2" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -239,74 +285,92 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", - "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "version": "7.24.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -320,6 +384,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -332,6 +397,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -346,6 +412,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -354,13 +421,25 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -370,6 +449,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -378,13 +458,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", - "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "version": "7.24.4", "dev": true, - "dependencies": { - "@babel/types": "^7.25.2" - }, + "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -397,6 +473,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -409,6 +486,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -421,6 +499,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -433,6 +512,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -445,6 +525,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -453,12 +534,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", - "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -472,6 +554,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -484,6 +567,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -496,6 +580,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -508,6 +593,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -520,6 +606,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -532,6 +619,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -544,6 +632,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -555,12 +644,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", - "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -570,30 +660,49 @@ } }, "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", - "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.2", + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -601,11 +710,26 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -623,6 +747,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -631,16 +756,18 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/types": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", - "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -651,12 +778,14 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@colors/colors": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", "engines": { "node": ">=0.1.90" } @@ -666,6 +795,7 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -678,6 +808,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -687,6 +818,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "license": "MIT", "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", @@ -731,9 +863,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -759,18 +891,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@fast-csv/format": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", @@ -808,15 +928,11 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" }, - "node_modules/@ioredis/commands": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", - "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -833,6 +949,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -840,10 +957,29 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -860,6 +996,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -870,11 +1007,29 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -891,6 +1046,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -900,6 +1056,7 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -909,6 +1066,7 @@ "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -926,6 +1084,7 @@ "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/reporters": "^29.7.0", @@ -968,32 +1127,12 @@ } } }, - "node_modules/@jest/core/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", @@ -1009,6 +1148,7 @@ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^29.7.0", "jest-snapshot": "^29.7.0" @@ -1022,6 +1162,7 @@ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3" }, @@ -1034,6 +1175,7 @@ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", @@ -1051,6 +1193,7 @@ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -1066,6 +1209,7 @@ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, + "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.7.0", @@ -1104,32 +1248,12 @@ } } }, - "node_modules/@jest/reporters/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, + "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -1142,6 +1266,7 @@ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.18", "callsites": "^3.0.0", @@ -1156,6 +1281,7 @@ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", @@ -1171,6 +1297,7 @@ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", @@ -1186,6 +1313,7 @@ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -1212,6 +1340,7 @@ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -1229,6 +1358,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1243,6 +1373,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1252,21 +1383,24 @@ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1276,6 +1410,7 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "license": "ISC", "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", @@ -1287,32 +1422,32 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@npmcli/fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", - "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", - "dependencies": { - "semver": "^7.3.5" - }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "14 || >=16.14" } }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -1322,13 +1457,15 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } @@ -1338,6 +1475,7 @@ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0" } @@ -1346,31 +1484,36 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -1384,6 +1527,7 @@ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } @@ -1393,16 +1537,18 @@ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } @@ -1412,6 +1558,7 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -1422,6 +1569,7 @@ "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } @@ -1431,6 +1579,7 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1440,6 +1589,7 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -1448,10 +1598,11 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "version": "4.17.43", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", + "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -1464,6 +1615,7 @@ "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1472,13 +1624,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz", "integrity": "sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/helmet": { "version": "0.0.47", "resolved": "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.47.tgz", "integrity": "sha512-TcHA/djjdUtrMtq/QAayVLrsgjNNZ1Uhtz0KhfH01mrmjH44E54DA1A0HNbwW0H/NBFqV+tGMo85ACuEhMXcdg==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } @@ -1487,12 +1641,13 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/http-proxy": { - "version": "1.17.15", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", - "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", "dependencies": { "@types/node": "*" } @@ -1507,25 +1662,19 @@ "http-proxy-middleware": "*" } }, - "node_modules/@types/http-proxy/node_modules/@types/node": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", - "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", - "dependencies": { - "undici-types": "~6.13.0" - } - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -1535,6 +1684,7 @@ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } @@ -1555,28 +1705,25 @@ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" } }, - "node_modules/@types/lodash": { - "version": "4.17.7", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", - "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", - "dev": true - }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/morgan": { "version": "1.9.9", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz", "integrity": "sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1585,22 +1732,17 @@ "version": "20.11.29", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz", "integrity": "sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA==", - "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } }, - "node_modules/@types/node/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, "node_modules/@types/pg": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.3.tgz", "integrity": "sha512-xocw4LvpDcj/Ta7bN52tLZm34mso5SZ0Q8fVC0UtD8s85Itip3YHvBeYZhBmC0OThpdOujHsxXtRbEIRxqXPXg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "pg-protocol": "*", @@ -1608,22 +1750,25 @@ } }, "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", + "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -1634,6 +1779,7 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -1644,30 +1790,35 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/strip-json-comments": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" }, "node_modules/@types/uuid": { "version": "9.0.8", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/xlsx": { "version": "0.0.36", @@ -1680,10 +1831,11 @@ } }, "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } @@ -1692,12 +1844,14 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/abbrev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -1706,6 +1860,7 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -1736,25 +1891,11 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", - "dev": true, - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk/node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -1763,6 +1904,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -1771,6 +1913,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", "dependencies": { "debug": "^4.3.4" }, @@ -1779,9 +1922,10 @@ } }, "node_modules/agent-base/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -1797,12 +1941,14 @@ "node_modules/agent-base/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -1812,14 +1958,14 @@ } }, "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", "dependencies": { "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -1847,6 +1993,7 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1856,6 +2003,7 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -1871,6 +2019,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -1879,20 +2028,24 @@ } }, "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "optional": true, + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -1903,6 +2056,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1915,6 +2069,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "license": "ISC", "optional": true }, "node_modules/archiver": { @@ -1954,95 +2109,113 @@ "node": ">= 6" } }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/archiver/node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/archiver/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/archiver/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" } }, "node_modules/are-we-there-yet": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "deprecated": "This package is no longer supported.", + "license": "ISC", "optional": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" } }, - "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "optional": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, - "node_modules/argparse/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/axios": { "version": "1.6.8", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -2054,6 +2227,7 @@ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", @@ -2075,6 +2249,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -2091,6 +2266,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -2107,6 +2283,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -2116,6 +2293,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -2131,6 +2309,7 @@ "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -2154,6 +2333,7 @@ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, + "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" @@ -2168,7 +2348,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -2193,6 +2374,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", "dependencies": { "safe-buffer": "5.1.2" }, @@ -2212,12 +2394,10 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "license": "MIT", "dependencies": { "buffers": "~0.1.1", "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" } }, "node_modules/binary-extensions": { @@ -2225,6 +2405,7 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -2236,6 +2417,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", "optional": true, "dependencies": { "file-uri-to-path": "1.0.0" @@ -2248,13 +2430,13 @@ "dev": true }, "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "license": "MIT", "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" } }, "node_modules/bluebird": { @@ -2289,26 +2471,28 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "fill-range": "^7.0.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.23.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", - "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -2324,11 +2508,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001646", - "electron-to-chromium": "^1.5.4", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -2342,6 +2527,7 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } @@ -2373,6 +2559,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "license": "MIT", "optional": true, "dependencies": { "buffer-alloc-unsafe": "^1.1.0", @@ -2383,12 +2570,14 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "license": "MIT", "optional": true }, "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", "engines": { "node": "*" } @@ -2397,13 +2586,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "license": "MIT", "optional": true }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/buffer-indexof-polyfill": { "version": "1.0.2", @@ -2417,18 +2608,11 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.1.tgz", "integrity": "sha512-IdnyU2jDHU65U63JuVQNTHiWjPRH0CS3aYd/WPaEwyX84rFdukhOduAVb1jwUScmb5X0JWPw8NZOrhoLMiyAHQ==", + "license": "MIT", "dependencies": { "long": "1.1.2" } }, - "node_modules/buffermaker/node_modules/long": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/long/-/long-1.1.2.tgz", - "integrity": "sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", @@ -2455,14 +2639,16 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/cacache": { - "version": "18.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", - "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", + "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -2485,33 +2671,47 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/cacache/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/cacache/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2526,6 +2726,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -2545,6 +2746,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2554,14 +2756,15 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001651", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", - "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", + "version": "1.0.30001605", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz", + "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==", "dev": true, "funding": [ { @@ -2576,12 +2779,14 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/cfb": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", "dependencies": { "adler-32": "~1.3.0", "crc-32": "~1.2.0" @@ -2594,11 +2799,9 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "license": "MIT/X11", "dependencies": { "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" } }, "node_modules/chalk": { @@ -2606,6 +2809,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2617,26 +2821,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/char-regex": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -2646,6 +2836,7 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -2666,10 +2857,13 @@ } }, "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "optional": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } }, "node_modules/ci-info": { "version": "3.9.0", @@ -2682,20 +2876,23 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cjs-module-lexer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", - "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", - "dev": true + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true, + "license": "MIT" }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", "engines": { "node": ">=6" } @@ -2705,6 +2902,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -2714,41 +2912,12 @@ "node": ">=12" } }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/cliui/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2758,6 +2927,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2767,56 +2937,21 @@ "node": ">=8" } }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "license": "MIT", "engines": { "node": ">=0.8" } }, - "node_modules/cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, + "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -2826,6 +2961,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -2835,6 +2971,7 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -2843,12 +2980,14 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" @@ -2858,6 +2997,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2868,12 +3008,14 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" }, "node_modules/color-string": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -2883,6 +3025,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -2890,12 +3033,14 @@ "node_modules/color/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" }, "node_modules/colorspace": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "license": "MIT", "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" @@ -2905,6 +3050,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -2926,10 +3072,24 @@ "node": ">= 10" } }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -2941,6 +3101,7 @@ "version": "1.7.4", "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -2958,6 +3119,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2965,18 +3127,21 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", "optional": true }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -3001,12 +3166,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3015,7 +3182,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookie": { "version": "0.6.0", @@ -3028,17 +3196,20 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" }, "node_modules/crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", "bin": { "crc32": "bin/crc32.njs" }, @@ -3058,11 +3229,25 @@ "node": ">= 10" } }, + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -3083,12 +3268,14 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3098,29 +3285,16 @@ "node": ">= 8" } }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/dayjs": { - "version": "1.11.13", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", - "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -3129,6 +3303,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "license": "MIT", "optional": true, "dependencies": { "mimic-response": "^1.0.0" @@ -3138,10 +3313,11 @@ } }, "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", "dev": true, + "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -3155,6 +3331,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", "optional": true, "engines": { "node": ">=4.0.0" @@ -3163,13 +3340,15 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3178,6 +3357,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -3194,6 +3374,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -3202,12 +3383,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", "optional": true }, "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "license": "Apache-2.0", "engines": { "node": ">=0.10" } @@ -3216,6 +3399,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3224,6 +3408,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -3233,6 +3418,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "license": "Apache-2.0", "optional": true, "bin": { "detect-libc": "bin/detect-libc.js" @@ -3246,6 +3432,7 @@ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3255,6 +3442,7 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -3264,6 +3452,7 @@ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -3273,6 +3462,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -3288,25 +3478,12 @@ "readable-stream": "^2.0.2" } }, - "node_modules/duplexer2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/dynamic-dedupe": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", "dev": true, + "license": "MIT", "dependencies": { "xtend": "^4.0.0" } @@ -3314,24 +3491,26 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", - "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", - "dev": true + "version": "1.4.726", + "dev": true, + "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -3340,19 +3519,22 @@ } }, "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3361,6 +3543,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -3370,6 +3553,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -3382,6 +3566,7 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "license": "MIT", "dependencies": { "once": "^1.4.0" } @@ -3391,6 +3576,7 @@ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -3399,31 +3585,11 @@ "node": ">=8.6" } }, - "node_modules/enquirer/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/enquirer/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", "engines": { "node": ">=6" } @@ -3431,7 +3597,8 @@ "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "license": "MIT" }, "node_modules/error": { "version": "7.0.2", @@ -3447,20 +3614,16 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, - "node_modules/error-ex/node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -3472,6 +3635,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -3481,6 +3645,7 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3488,21 +3653,14 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/escodegen": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", "estraverse": "^4.2.0", @@ -3520,16 +3678,54 @@ "source-map": "~0.6.1" } }, - "node_modules/escodegen/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" }, "engines": { - "node": ">=4" + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "license": "MIT", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" } }, "node_modules/eslint": { @@ -3591,6 +3787,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -3604,6 +3801,7 @@ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^1.1.0" }, @@ -3619,6 +3817,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=4" } @@ -3628,6 +3827,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10" } @@ -3648,20 +3848,12 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/eslint/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/eslint/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -3680,98 +3872,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "node_modules/eslint/node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/eslint/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/eslint/node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } + "license": "MIT" }, "node_modules/espree": { "version": "7.3.1", @@ -3797,22 +3903,24 @@ } }, "node_modules/esprima": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", - "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=0.4.0" + "node": ">=4" } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -3825,6 +3933,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3834,6 +3943,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -3846,6 +3956,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3854,6 +3965,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3862,6 +3974,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -3870,6 +3983,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3898,6 +4012,19 @@ "node": ">=8.3.0" } }, + "node_modules/exceljs/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/exceljs/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -3911,6 +4038,7 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -3942,6 +4070,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", "optional": true, "engines": { "node": ">=6" @@ -3952,6 +4081,7 @@ "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", @@ -3966,7 +4096,8 @@ "node_modules/exponential-backoff": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "license": "Apache-2.0" }, "node_modules/express": { "version": "4.19.2", @@ -4026,7 +4157,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/fast-csv": { "version": "4.3.6", @@ -4043,29 +4175,28 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" - }, - "node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "license": "MIT" }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } @@ -4073,13 +4204,15 @@ "node_modules/fecha": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -4091,12 +4224,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT", "optional": true }, "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4108,6 +4243,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -4126,6 +4262,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -4139,6 +4276,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -4148,32 +4286,18 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fn.name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" }, "node_modules/follow-redirects": { "version": "1.15.6", @@ -4185,6 +4309,7 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -4195,9 +4320,10 @@ } }, "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -4213,6 +4339,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { "node": ">=14" }, @@ -4224,6 +4351,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -4237,6 +4365,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4245,6 +4374,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -4253,6 +4383,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4260,12 +4391,14 @@ "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -4276,21 +4409,8 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" }, "node_modules/fstream": { "version": "1.0.12", @@ -4307,10 +4427,23 @@ "node": ">=0.6" } }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4319,13 +4452,14 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", - "deprecated": "This package is no longer supported.", + "license": "ISC", "optional": true, "dependencies": { "aproba": "^1.0.3", @@ -4338,11 +4472,35 @@ "wide-align": "^1.1.0" } }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -4352,6 +4510,7 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -4360,6 +4519,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -4379,6 +4539,7 @@ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -4388,6 +4549,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -4399,13 +4561,14 @@ "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT", "optional": true }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4426,6 +4589,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -4448,19 +4612,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globals/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -4471,13 +4627,15 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4486,6 +4644,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -4497,6 +4656,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4508,6 +4668,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4519,17 +4680,20 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", "optional": true }, "node_modules/hash-sum": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", - "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==" + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "license": "MIT" }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -4541,6 +4705,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", + "license": "MIT", "engines": { "node": ">=16.0.0" } @@ -4566,17 +4731,20 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "license": "BSD-2-Clause" }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -4605,6 +4773,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -4614,9 +4783,10 @@ } }, "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -4632,7 +4802,8 @@ "node_modules/http-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" }, "node_modules/http-proxy-middleware": { "version": "3.0.0", @@ -4651,9 +4822,9 @@ } }, "node_modules/http-proxy-middleware/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -4672,9 +4843,10 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -4684,9 +4856,10 @@ } }, "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -4702,13 +4875,15 @@ "node_modules/https-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -4717,6 +4892,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -4755,7 +4931,8 @@ "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -4774,10 +4951,11 @@ } }, "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -4796,6 +4974,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -4804,6 +4983,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", "engines": { "node": ">=8" } @@ -4812,7 +4992,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -4821,62 +5001,21 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC", "optional": true }, - "node_modules/ioredis": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.4.1.tgz", - "integrity": "sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==", - "dependencies": { - "@ioredis/commands": "^1.1.1", - "cluster-key-slot": "^1.1.0", - "debug": "^4.3.4", - "denque": "^2.1.0", - "lodash.defaults": "^4.2.0", - "lodash.isarguments": "^3.1.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0", - "standard-as-callback": "^2.1.0" - }, - "engines": { - "node": ">=12.22.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ioredis" - } - }, - "node_modules/ioredis/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/ioredis/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -4885,24 +5024,34 @@ "node": ">= 12" } }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -4911,15 +5060,13 @@ } }, "node_modules/is-core-module": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", - "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4929,6 +5076,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4937,6 +5085,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "license": "MIT", "optional": true, "dependencies": { "number-is-nan": "^1.0.0" @@ -4950,6 +5099,7 @@ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -4958,6 +5108,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -4968,12 +5119,14 @@ "node_modules/is-lambda": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "license": "MIT" }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -4993,6 +5146,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -5003,27 +5157,31 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", + "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -5035,23 +5193,12 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -5066,6 +5213,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -5076,10 +5224,11 @@ } }, "node_modules/istanbul-lib-source-maps/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -5096,13 +5245,15 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/istanbul-reports": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -5112,12 +5263,16 @@ } }, "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, + "engines": { + "node": ">=14" + }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -5153,6 +5308,7 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -5179,6 +5335,7 @@ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, + "license": "MIT", "dependencies": { "execa": "^5.0.0", "jest-util": "^29.7.0", @@ -5188,26 +5345,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-changed-files/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-circus": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -5234,19 +5377,38 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-circus/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", "dev": true, + "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, "node_modules/jest-config": { @@ -5254,6 +5416,7 @@ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.7.0", @@ -5294,23 +5457,12 @@ } } }, - "node_modules/jest-config/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-diff": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", @@ -5326,6 +5478,7 @@ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, + "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" }, @@ -5338,6 +5491,7 @@ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -5354,6 +5508,7 @@ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -5371,6 +5526,7 @@ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -5380,6 +5536,7 @@ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -5405,6 +5562,7 @@ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" @@ -5418,6 +5576,7 @@ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.7.0", @@ -5433,6 +5592,7 @@ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -5448,11 +5608,26 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-message-util/node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/jest-mock": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -5467,6 +5642,7 @@ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -5484,6 +5660,7 @@ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -5493,6 +5670,7 @@ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -5513,6 +5691,7 @@ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, + "license": "MIT", "dependencies": { "jest-regex-util": "^29.6.3", "jest-snapshot": "^29.7.0" @@ -5526,6 +5705,7 @@ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/environment": "^29.7.0", @@ -5553,26 +5733,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-runtime": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -5606,6 +5772,7 @@ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -5632,23 +5799,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -5666,6 +5822,7 @@ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -5683,6 +5840,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -5695,6 +5853,7 @@ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", @@ -5714,6 +5873,7 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", @@ -5729,6 +5889,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -5739,50 +5900,19 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jest/node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -5791,29 +5921,18 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/js-yaml/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/jsbn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -5825,13 +5944,15 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "1.0.0", @@ -5842,13 +5963,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -5860,16 +5983,30 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "license": "MIT", "dependencies": { "esprima": "1.2.2", "static-eval": "2.0.2", "underscore": "1.12.1" } }, + "node_modules/jsonpath/node_modules/esprima": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -5877,24 +6014,11 @@ "setimmediate": "^1.0.5" } }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/kafka-node": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz", "integrity": "sha512-dD2ga5gLcQhsq1yNoQdy1MU4x4z7YnXM5bcG9SdQuiNr5KKuAmXixH1Mggwdah5o7EfholFbcNDPSVA6BIfaug==", + "license": "MIT", "dependencies": { "async": "^2.6.2", "binary": "~0.3.0", @@ -5917,50 +6041,11 @@ "snappy": "^6.0.1" } }, - "node_modules/kafka-node/node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/kafka-node/node_modules/bl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", - "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", - "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/kafka-node/node_modules/denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/kafka-node/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/kafka-node/node_modules/uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "license": "MIT", "bin": { "uuid": "bin/uuid" } @@ -5970,6 +6055,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -5979,6 +6065,7 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5986,7 +6073,8 @@ "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" }, "node_modules/lazystream": { "version": "1.0.1", @@ -5999,36 +6087,25 @@ "node": ">= 0.6.3" } }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -6038,6 +6115,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", "dependencies": { "immediate": "~3.0.5" } @@ -6046,7 +6124,8 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/listenercount": { "version": "1.0.1", @@ -6058,6 +6137,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -6068,7 +6148,8 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" }, "node_modules/lodash.defaults": { "version": "4.2.0", @@ -6095,11 +6176,6 @@ "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==" }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" - }, "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", @@ -6134,7 +6210,8 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.union": { "version": "4.6.0", @@ -6147,9 +6224,10 @@ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" }, "node_modules/logform": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", - "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "license": "MIT", "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -6165,26 +6243,34 @@ "node_modules/logform/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/long": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", - "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/long/-/long-1.1.2.tgz", + "integrity": "sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q==", + "license": "Apache-2.0", "engines": { "node": ">=0.6" } }, "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -6195,28 +6281,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/make-fetch-happen": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", - "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "license": "ISC", "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", @@ -6227,7 +6303,6 @@ "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", - "proc-log": "^4.2.0", "promise-retry": "^2.0.1", "ssri": "^10.0.0" }, @@ -6235,19 +6310,12 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/make-fetch-happen/node_modules/proc-log": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", - "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } @@ -6256,6 +6324,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6263,28 +6332,32 @@ "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "license": "MIT" }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "license": "MIT", "dependencies": { - "braces": "^3.0.3", + "braces": "^3.0.2", "picomatch": "^2.3.1" }, "engines": { @@ -6295,6 +6368,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -6306,6 +6380,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6314,6 +6389,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -6326,6 +6402,7 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6334,6 +6411,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "license": "MIT", "optional": true, "engines": { "node": ">=4" @@ -6343,6 +6421,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6354,14 +6433,16 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -6370,6 +6451,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -6378,9 +6460,10 @@ } }, "node_modules/minipass-fetch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", - "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -6397,6 +6480,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6408,6 +6492,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6415,10 +6500,17 @@ "node": ">=8" } }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6430,6 +6522,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6437,10 +6530,17 @@ "node": ">=8" } }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6452,6 +6552,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6459,10 +6560,17 @@ "node": ">=8" } }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -6475,6 +6583,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6482,10 +6591,17 @@ "node": ">=8" } }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, @@ -6497,6 +6613,7 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", @@ -6512,6 +6629,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -6522,30 +6640,35 @@ "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/nan": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", - "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", + "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", + "license": "MIT", "optional": true }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "license": "MIT", "optional": true }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6553,21 +6676,34 @@ "node_modules/nested-error-stacks": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", - "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", + "license": "MIT" }, "node_modules/node-abi": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", + "license": "MIT", "optional": true, "dependencies": { "semver": "^5.4.1" } }, + "node_modules/node-abi/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/node-cache": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "license": "MIT", "dependencies": { "clone": "2.x" }, @@ -6602,33 +6738,47 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/node-gyp/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", + "engines": { + "node": ">=16" + } + }, "node_modules/node-gyp/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6639,38 +6789,46 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, "bin": { - "semver": "bin/semver.js" + "node-which": "bin/which.js" }, "engines": { - "node": ">=10" + "node": "^16.13.0 || >=18.0.0" } }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true, + "license": "MIT" }, "node_modules/noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==", + "license": "MIT", "optional": true }, "node_modules/nopt": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", - "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "license": "ISC", "dependencies": { "abbrev": "^2.0.0" }, @@ -6685,6 +6843,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6694,6 +6853,7 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -6705,7 +6865,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "deprecated": "This package is no longer supported.", + "license": "ISC", "optional": true, "dependencies": { "are-we-there-yet": "~1.1.2", @@ -6718,6 +6878,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -6727,18 +6888,17 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "engines": { - "node": ">= 0.4" - }, + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6747,12 +6907,14 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -6764,6 +6926,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -6772,6 +6935,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -6780,6 +6944,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", "dependencies": { "fn.name": "1.x.x" } @@ -6789,6 +6954,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -6810,19 +6976,22 @@ "node_modules/optional": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz", - "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==" + "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==", + "license": "MIT" }, "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "license": "MIT", "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -6832,21 +7001,23 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6857,6 +7028,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -6864,10 +7036,27 @@ "node": ">=8" } }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-map": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -6883,19 +7072,16 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" - }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" }, "node_modules/parent-module": { "version": "1.0.1", @@ -6914,6 +7100,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -6931,6 +7118,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -6940,6 +7128,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6948,6 +7137,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6956,6 +7146,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { "node": ">=8" } @@ -6964,27 +7155,39 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "license": "MIT" }, "node_modules/pg": { "version": "8.12.0", @@ -7018,19 +7221,22 @@ "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/pg-connection-string": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", "dev": true, + "license": "ISC", "engines": { "node": ">=4.0.0" } @@ -7040,6 +7246,7 @@ "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", "dev": true, + "license": "ISC", "engines": { "node": ">=4" } @@ -7049,6 +7256,7 @@ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", "dev": true, + "license": "MIT", "peerDependencies": { "pg": ">=8.0" } @@ -7057,13 +7265,15 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pg-types": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", "dev": true, + "license": "MIT", "dependencies": { "pg-int8": "1.0.1", "pg-numeric": "1.0.2", @@ -7082,6 +7292,7 @@ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", "dev": true, + "license": "MIT", "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", @@ -7098,6 +7309,7 @@ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -7107,6 +7319,7 @@ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7116,6 +7329,7 @@ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7125,6 +7339,7 @@ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", "dev": true, + "license": "MIT", "dependencies": { "xtend": "^4.0.0" }, @@ -7137,20 +7352,23 @@ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", "dev": true, + "license": "MIT", "dependencies": { "split2": "^4.1.0" } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -7163,6 +7381,7 @@ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -7172,6 +7391,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -7184,6 +7404,7 @@ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" } @@ -7193,6 +7414,7 @@ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", "dev": true, + "license": "MIT", "dependencies": { "obuf": "~1.1.2" }, @@ -7205,6 +7427,7 @@ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" } @@ -7214,6 +7437,7 @@ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" } @@ -7222,12 +7446,14 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prebuild-install": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz", "integrity": "sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg==", + "license": "MIT", "optional": true, "dependencies": { "detect-libc": "^1.0.3", @@ -7255,9 +7481,11 @@ } }, "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -7267,6 +7495,7 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -7281,6 +7510,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7292,6 +7522,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -7307,13 +7538,15 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -7334,6 +7567,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "license": "MIT", "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -7346,6 +7580,7 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", "engines": { "node": ">= 4" } @@ -7355,6 +7590,7 @@ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, + "license": "MIT", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -7366,12 +7602,14 @@ "node_modules/property-expr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", - "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "license": "MIT" }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -7383,12 +7621,14 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" }, "node_modules/pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "license": "MIT", "optional": true, "dependencies": { "end-of-stream": "^1.1.0", @@ -7399,7 +7639,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -7418,12 +7658,14 @@ "type": "opencollective", "url": "https://opencollective.com/fast-check" } - ] + ], + "license": "MIT" }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -7438,6 +7680,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7446,6 +7689,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -7460,6 +7704,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "optional": true, "dependencies": { "deep-extend": "^0.6.0", @@ -7471,23 +7716,36 @@ "rc": "cli.js" } }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true, + "license": "MIT" }, "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "node_modules/readdir-glob": { @@ -7522,6 +7780,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -7529,30 +7788,12 @@ "node": ">=8.10.0" } }, - "node_modules/redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", - "engines": { - "node": ">=4" - } - }, - "node_modules/redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", - "dependencies": { - "redis-errors": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -7565,6 +7806,7 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7573,6 +7815,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7587,6 +7830,7 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, + "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -7604,6 +7848,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -7616,6 +7861,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7634,6 +7880,7 @@ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -7642,31 +7889,38 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", "integrity": "sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ==", + "license": "MIT", "engines": { "node": "*" } }, "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" }, "node_modules/safe-stable-stringify": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "license": "MIT", "engines": { "node": ">=10" } @@ -7674,12 +7928,14 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "license": "ISC" }, "node_modules/saxes": { "version": "5.0.1", @@ -7693,18 +7949,43 @@ } }, "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "optional": true, + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -7727,12 +8008,14 @@ "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -7747,12 +8030,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC", "optional": true }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -7768,17 +8053,20 @@ "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -7790,6 +8078,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { "node": ">=8" } @@ -7798,6 +8087,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -7815,7 +8105,8 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "devOptional": true + "devOptional": true, + "license": "ISC" }, "node_modules/simple-concat": { "version": "1.0.1", @@ -7835,12 +8126,14 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "optional": true }, "node_modules/simple-get": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "license": "MIT", "optional": true, "dependencies": { "decompress-response": "^3.3.0", @@ -7852,21 +8145,30 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", "dependencies": { "is-arrayish": "^0.3.1" } }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7876,6 +8178,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -7888,26 +8191,12 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7916,6 +8205,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -7926,6 +8216,7 @@ "resolved": "https://registry.npmjs.org/snappy/-/snappy-6.3.5.tgz", "integrity": "sha512-lonrUtdp1b1uDn1dbwgQbBsb5BbaiLeKq+AGwOk2No+en+VvJThwmtztwulEQsLinRF681pBqib0NUZaizKLIA==", "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "bindings": "^1.3.1", @@ -7934,9 +8225,10 @@ } }, "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", + "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "license": "MIT", "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -7947,22 +8239,24 @@ } }, "node_modules/socks-proxy-agent": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.8.3" + "socks": "^2.7.1" }, "engines": { "node": ">= 14" } }, "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -7978,13 +8272,15 @@ "node_modules/socks-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "devOptional": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -7994,6 +8290,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -8004,19 +8301,23 @@ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 10.x" } }, "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/ssf": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", "dependencies": { "frac": "~1.1.2" }, @@ -8025,9 +8326,10 @@ } }, "node_modules/ssri": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", - "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -8039,6 +8341,7 @@ "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", "engines": { "node": "*" } @@ -8048,6 +8351,7 @@ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -8060,19 +8364,16 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/standard-as-callback": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", - "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" - }, "node_modules/static-eval": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", + "license": "MIT", "dependencies": { "escodegen": "^1.8.1" } @@ -8081,6 +8382,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8089,6 +8391,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -8098,6 +8401,7 @@ "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, + "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -8106,27 +8410,6 @@ "node": ">=10" } }, - "node_modules/string-length/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", @@ -8136,6 +8419,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "license": "MIT", "optional": true, "dependencies": { "code-point-at": "^1.0.0", @@ -8151,48 +8435,40 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + }, "engines": { "node": ">=8" } }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "license": "MIT", + "optional": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/strip-ansi": { + "node_modules/string-width/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "license": "MIT", "optional": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -8201,28 +8477,37 @@ "node": ">=0.10.0" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", + "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" - } - }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + }, "engines": { "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8232,17 +8517,22 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "devOptional": true, + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/supports-color": { @@ -8250,6 +8540,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -8262,6 +8553,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -8274,6 +8566,7 @@ "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "ajv": "^8.0.1", "lodash.truncate": "^4.4.2", @@ -8285,26 +8578,12 @@ "node": ">=10.0.0" } }, - "node_modules/table/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/table/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8314,6 +8593,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -8323,22 +8603,11 @@ "node": ">=8" } }, - "node_modules/table/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/tar": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -8355,6 +8624,7 @@ "version": "1.16.3", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "license": "MIT", "optional": true, "dependencies": { "chownr": "^1.0.1", @@ -8363,45 +8633,29 @@ "tar-stream": "^1.1.2" } }, - "node_modules/tar-fs/node_modules/bl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "optional": true, - "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC", + "optional": true }, "node_modules/tar-fs/node_modules/pump": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "license": "MIT", "optional": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, - "node_modules/tar-fs/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "optional": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/tar-fs/node_modules/tar-stream": { + "node_modules/tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "license": "MIT", "optional": true, "dependencies": { "bl": "^1.0.0", @@ -8416,33 +8670,22 @@ "node": ">= 0.8.0" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/tar-stream/node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "license": "MIT", + "optional": true, "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar/node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "engines": { - "node": ">=10" + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" } }, "node_modules/tar/node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -8454,6 +8697,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -8465,6 +8709,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", "engines": { "node": ">=8" } @@ -8473,6 +8718,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -8480,6 +8726,12 @@ "node": ">=10" } }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/tdigest": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", @@ -8494,6 +8746,7 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -8506,13 +8759,15 @@ "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/thriftrw": { "version": "3.11.4", @@ -8530,10 +8785,19 @@ "node": ">= 0.10.x" } }, + "node_modules/thriftrw/node_modules/long": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", + "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/tiny-case": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", - "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", + "license": "MIT" }, "node_modules/tmp": { "version": "0.2.3", @@ -8547,12 +8811,14 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "license": "MIT", "optional": true }, "node_modules/to-fast-properties": { @@ -8560,6 +8826,7 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -8568,6 +8835,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -8579,6 +8847,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } @@ -8586,21 +8855,21 @@ "node_modules/toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "license": "MIT" }, "node_modules/traverse": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "engines": { - "node": "*" - } + "license": "MIT/X11" }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, + "license": "MIT", "bin": { "tree-kill": "cli.js" } @@ -8609,6 +8878,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", "engines": { "node": ">= 14.0.0" } @@ -8618,6 +8888,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -8661,6 +8932,7 @@ "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": "^3.5.1", "dynamic-dedupe": "^0.3.0", @@ -8695,6 +8967,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -8702,11 +8975,25 @@ "node": ">=10" } }, + "node_modules/ts-node-dev/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/ts-node/node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -8719,6 +9006,7 @@ "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", "dev": true, + "license": "MIT", "dependencies": { "@types/strip-bom": "^3.0.0", "@types/strip-json-comments": "0.0.30", @@ -8731,14 +9019,26 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/tsconfig/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", "optional": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -8748,11 +9048,13 @@ } }, "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", "dependencies": { - "prelude-ls": "~1.1.2" + "prelude-ls": "^1.2.1" }, "engines": { "node": ">= 0.8.0" @@ -8763,25 +9065,25 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -8795,6 +9097,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8806,17 +9109,20 @@ "node_modules/underscore": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", - "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", + "license": "MIT" }, "node_modules/undici-types": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", - "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" }, "node_modules/unique-filename": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -8828,6 +9134,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -8839,6 +9146,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8860,24 +9168,10 @@ "setimmediate": "~1.0.4" } }, - "node_modules/unzipper/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, "funding": [ { @@ -8893,9 +9187,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.1.1", + "picocolors": "^1.0.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -8908,7 +9203,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -8916,12 +9211,14 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -8934,6 +9231,7 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -8942,19 +9240,22 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -8968,6 +9269,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8977,45 +9279,41 @@ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } }, "node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { - "isexe": "^3.1.1" + "isexe": "^2.0.0" }, "bin": { - "node-which": "bin/which.js" + "node-which": "bin/node-which" }, "engines": { - "node": "^16.13.0 || >=18.0.0" + "node": ">= 8" } }, "node_modules/which-pm-runs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "license": "MIT", "optional": true, "engines": { "node": ">=4" } }, - "node_modules/which/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "engines": { - "node": ">=16" - } - }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", "optional": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" @@ -9025,6 +9323,7 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz", "integrity": "sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w==", + "license": "MIT", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", @@ -9043,22 +9342,58 @@ } }, "node_modules/winston-transport": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.1.tgz", - "integrity": "sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", + "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", + "license": "MIT", "dependencies": { - "logform": "^2.6.1", - "readable-stream": "^3.6.2", + "logform": "^2.3.2", + "readable-stream": "^3.6.0", "triple-beam": "^1.3.0" }, "engines": { "node": ">= 12.0.0" } }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "license": "MIT" + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/wmf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -9067,6 +9402,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -9075,21 +9411,24 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -9100,43 +9439,24 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { "node": ">=8" } @@ -9145,6 +9465,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9154,68 +9475,43 @@ "node": ">=8" } }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -9248,6 +9544,7 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz", "integrity": "sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw==", + "license": "MIT", "dependencies": { "cfb": "^1.1.3", "jszip": "^3.2.2", @@ -9269,6 +9566,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", "engines": { "node": ">=0.4" } @@ -9278,20 +9576,24 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -9310,30 +9612,17 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/yargs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -9343,6 +9632,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9352,23 +9642,12 @@ "node": ">=8" } }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -9378,6 +9657,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -9389,6 +9669,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz", "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==", + "license": "MIT", "dependencies": { "property-expr": "^2.0.5", "tiny-case": "^1.0.3", @@ -9396,6 +9677,18 @@ "type-fest": "^2.19.0" } }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zip-stream": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", @@ -9428,6 +9721,19 @@ "engines": { "node": ">= 10" } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } } } } diff --git a/health-services/project-factory/package.json b/health-services/project-factory/package.json index 5a80dcc7147..a91771378fa 100644 --- a/health-services/project-factory/package.json +++ b/health-services/project-factory/package.json @@ -1,6 +1,6 @@ { "name": "project-factory", - "version": "0.3.0", + "version": "0.1.0", "main": "src/server/index.ts", "author": "Jagankumar ", "description": "Backend For Frontend service", @@ -10,11 +10,11 @@ "build": "yarn run build-ts", "build-ts": "tsc", "clean": "rm -rf ./dist", - "serve": "if [ \"$DEBUG\" = \"true\" ]; then node --inspect=0.0.0.0:9229 dist/index.js; else node dist/index.js; fi", + "serve": "node dist/index.js", "start": "yarn run dev", "test": "jest", "dev": "ts-node-dev --respawn src/server/index.ts", - "prod": "if [ \"$DEBUG\" = \"true\" ]; then cp tsconfig.debug.json tsconfig.json; fi && yarn build && yarn serve", + "prod": "yarn build && yarn serve", "watch-ts": "tsc --watch" }, "repository": { @@ -26,7 +26,7 @@ "axios": "1.6.8", "body-parser": "^1.20.2", "compression": "1.7.4", - "exceljs": "^4.4.0", + "exceljs": "4.4.0", "express": "^4.19.2", "hash-sum": "2.0.0", "helmet": "7.1.0", @@ -54,7 +54,6 @@ "@types/http-proxy-middleware": "^1.0.0", "@types/jaeger-client": "^3.18.7", "@types/jest": "29.5.12", - "@types/lodash": "^4.17.5", "@types/morgan": "1.9.9", "@types/node": "20.11.29", "@types/pg": "8.11.3", diff --git a/health-services/project-factory/postman_collection.json b/health-services/project-factory/postman_collection.json index d99524df3c1..5780448766a 100644 --- a/health-services/project-factory/postman_collection.json +++ b/health-services/project-factory/postman_collection.json @@ -1,13 +1,18 @@ { "info": { - "_postman_id": "42be4494-a788-4977-b8f2-e14894cce42b", - "name": "Project-Factory Collection", + "_postman_id": "4faeccce-fc50-4dfb-8fef-d973aca136c4", + "name": "Project factory", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "28207698" + "_exporter_id": "18845214" }, "item": [ { - "name": "campain-manage-create Copy", + "name": "facility data generate(template generate)", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, "request": { "method": "POST", "header": [ @@ -25,7 +30,8 @@ }, { "key": "content-type", - "value": "application/json" + "value": "application/json", + "disabled": true }, { "key": "cookie", @@ -66,37 +72,65 @@ { "key": "user-agent", "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" } ], "body": { "mode": "raw", - "raw": "{\n // 43cfaf3f-f31f-492f-afeb-cebe4f4301e8\n // d71a1963-27a8-4300-a1c4-2ec99e95331b multiplesheet\n // 6c091ddb-523e-4afd-8a81-afe94196d080 without matching sheetName\n // for unifieddev\n // 1d27af7d-3736-408d-b9bc-796c92fd5f4b multiplesheet\n \"Campaign\": {\n // \"id\": \"string\",\n // \"campaignNo\": \"string\",\n \"hierarchyType\": \"string\",\n \"tenantId\": \"mz\",\n \"campaignName\": \"string\",\n \"boundaryCode\": \"mz\",\n \"startDate\": 1677594987,\n // \"endDate\": 9776881655,\n \"endDate\": 1677594987,\n \"projectType\": \"Household Based Project\",\n \"CampaignDetails\": [\n {\n \"boundaryCode\": \"f5F6xAskA05\",\n \"boundaryType\": \"Provincia\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 300,\n \"target\": 250,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": \"mz\",\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n \"867ba408-1b82-4746-8274-eb916e625fea\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"staff\"\n }\n ]\n },\n {\n \"boundaryCode\": \"f5F6xAskA05\",\n \"boundaryType\": \"Provincia\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 700,\n \"target\": 600,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": \"mz\",\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n \"867ba408-1b82-4746-8274-eb916e625fea\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"staff\"\n }\n ]\n },\n {\n \"boundaryCode\": \"mz\",\n \"boundaryType\": \"Country\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 1000,\n \"target\": 800,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": null,\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n \"F-2024-03-21-000882\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"facility\"\n }\n ]\n },\n {\n \"boundaryCode\": \"mz\",\n \"boundaryType\": \"Country\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 450,\n \"target\": 350,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": null,\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n // \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\"\n \"PVAR-2024-03-21-000052\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"resource\"\n // \"type\": \"staff|resource|facility\"\n }\n ]\n }\n // Add more entries as needed...\n ],\n \"deliveryRules\": [\n {\n \"startDate\": \"string\",\n \"endDate\": \"string\",\n \"cycle\": \"string\"\n }\n ],\n \"additionalDetails\": {}\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"e45445a1-6891-4a76-a4e6-528e1dd24946\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1710912592752|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" + "raw": "{\n \"RequestInfo\":{\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"b902a184-4582-41f8-8144-99930548631d\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1716457221446|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" }, "url": { - "raw": "http://localhost:8080/project-factory/v1/project-type/createCampaign", - "protocol": "http", + "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=boundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=3b331cd6-c0e9-4fd4-9d15-9212ba51706c", + "protocol": "https", "host": [ - "localhost" + "unified-uat", + "digit", + "org" ], - "port": "8080", "path": [ "project-factory", "v1", - "project-type", - "createCampaign" + "data", + "_generate" + ], + "query": [ + { + "key": "tenantId", + "value": "mz" + }, + { + "key": "type", + "value": "boundary" + }, + { + "key": "forceUpdate", + "value": "true" + }, + { + "key": "hierarchyType", + "value": "ADMIN" + }, + { + "key": "campaignId", + "value": "3b331cd6-c0e9-4fd4-9d15-9212ba51706c" + } ] } }, "response": [] }, { - "name": "mdms bulk search Copy", + "name": "boundary data generate(template generate)", "request": { "method": "POST", "header": [ { "key": "authority", - "value": "unified-dev.digit.org" + "value": "unified-uat.digit.org" }, { "key": "accept", @@ -108,19 +142,19 @@ }, { "key": "content-type", - "value": "application/json" + "value": "application/json;charset=UTF-8" }, { "key": "cookie", - "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0; PGADMIN_LANGUAGE=en" }, { "key": "origin", - "value": "https://unified-dev.digit.org" + "value": "https://unified-uat.digit.org" }, { "key": "referer", - "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?key=7&preview=false&id=2c948509-4245-4df7-b46b-9cabd5cdb577" }, { "key": "sec-ch-ua", @@ -153,20 +187,21 @@ ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1710912592752|en_MZ\",\n \"plainAccessRequest\": {}\n }\n}" + "raw": "{\"Filters\":null,\"RequestInfo\":{\"apiId\":\"Rainmaker\",\"authToken\":\"f364ac54-8e9a-49ec-8aff-a3df278bd68d\",\"userInfo\":{\"id\":1052,\"uuid\":\"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\"userName\":\"UATMZ\",\"name\":\"UATMZ\",\"mobileNumber\":\"8998988112\",\"emailId\":null,\"locale\":null,\"type\":\"EMPLOYEE\",\"roles\":[{\"name\":\"System Administrator\",\"code\":\"SYSTEM_ADMINISTRATOR\",\"tenantId\":\"mz\"},{\"name\":\"Campaign Manager\",\"code\":\"CAMPAIGN_MANAGER\",\"tenantId\":\"mz\"},{\"name\":\"Localisation admin\",\"code\":\"LOC_ADMIN\",\"tenantId\":\"mz\"},{\"name\":\"MDMS ADMIN\",\"code\":\"MDMS_ADMIN\",\"tenantId\":\"mz\"}],\"active\":true,\"tenantId\":\"mz\",\"permanentCity\":null},\"msgId\":\"1716892389916|en_IN\",\"plainAccessRequest\":{}}}" }, "url": { - "raw": "http://localhost:8080/mdms-bff/v1/mdmsbulk/search?tenantId=mz&schemaName=Dummy.dummy", - "protocol": "http", + "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=boundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=2c948509-4245-4df7-b46b-9cabd5cdb577", + "protocol": "https", "host": [ - "localhost" + "unified-uat", + "digit", + "org" ], - "port": "8080", "path": [ - "mdms-bff", + "project-factory", "v1", - "mdmsbulk", - "search" + "data", + "_generate" ], "query": [ { @@ -174,8 +209,20 @@ "value": "mz" }, { - "key": "schemaName", - "value": "Dummy.dummy" + "key": "type", + "value": "boundary" + }, + { + "key": "forceUpdate", + "value": "true" + }, + { + "key": "hierarchyType", + "value": "ADMIN" + }, + { + "key": "campaignId", + "value": "2c948509-4245-4df7-b46b-9cabd5cdb577" } ] } @@ -183,12 +230,7 @@ "response": [] }, { - "name": "campaign-generate Copy", - "protocolProfileBehavior": { - "disabledSystemHeaders": { - "content-type": true - } - }, + "name": "User generate data(template generate)", "request": { "method": "POST", "header": [ @@ -218,7 +260,7 @@ }, { "key": "referer", - "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?id=22f77798-3645-44b3-98ee-cc5c0ff2888c&draft=true&fetchBoundary=true&key=8&preview=false&skip=false" + "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?key=7&preview=false&id=2c948509-4245-4df7-b46b-9cabd5cdb577" }, { "key": "sec-ch-ua", @@ -251,15 +293,16 @@ ], "body": { "mode": "raw", - "raw": "{\n \"ResourceDetails\": {\n \"type\": \"facility\",\n \"hierarchyType\": \"ADMIN\",\n \"tenantId\": \"mz\",\n \"fileStoreId\": \"fd451260-67e8-4d57-a7bf-81734b0dccc7\",\n \"action\": \"validate\",\n \"campaignId\": \"22f77798-3645-44b3-98ee-cc5c0ff2888c\",\n \"additionalDetails\": {}\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1052,\n \"uuid\": \"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\n \"userName\": \"UATMZ\",\n \"name\": \"UATMZ\",\n \"mobileNumber\": \"8998988112\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS ADMIN\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1716899532287|en_IN\",\n \"plainAccessRequest\": {}\n }\n}" + "raw": "{\"RequestInfo\":{\"apiId\":\"Rainmaker\",\"authToken\":\"f364ac54-8e9a-49ec-8aff-a3df278bd68d\",\"userInfo\":{\"id\":1052,\"uuid\":\"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\"userName\":\"UATMZ\",\"name\":\"UATMZ\",\"mobileNumber\":\"8998988112\",\"emailId\":null,\"locale\":null,\"type\":\"EMPLOYEE\",\"roles\":[{\"name\":\"System Administrator\",\"code\":\"SYSTEM_ADMINISTRATOR\",\"tenantId\":\"mz\"},{\"name\":\"Campaign Manager\",\"code\":\"CAMPAIGN_MANAGER\",\"tenantId\":\"mz\"},{\"name\":\"Localisation admin\",\"code\":\"LOC_ADMIN\",\"tenantId\":\"mz\"},{\"name\":\"MDMS ADMIN\",\"code\":\"MDMS_ADMIN\",\"tenantId\":\"mz\"}],\"active\":true,\"tenantId\":\"mz\",\"permanentCity\":null},\"msgId\":\"1716892389917|en_IN\",\"plainAccessRequest\":{}}}" }, "url": { - "raw": "http://localhost:8080/project-factory/v1/data/_generate?tenantId=mz&type=userWithBoundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=3b331cd6-c0e9-4fd4-9d15-9212ba51706c", - "protocol": "http", + "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=userWithBoundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=2c948509-4245-4df7-b46b-9cabd5cdb577", + "protocol": "https", "host": [ - "localhost" + "unified-uat", + "digit", + "org" ], - "port": "8080", "path": [ "project-factory", "v1", @@ -285,7 +328,7 @@ }, { "key": "campaignId", - "value": "3b331cd6-c0e9-4fd4-9d15-9212ba51706c" + "value": "2c948509-4245-4df7-b46b-9cabd5cdb577" } ] } @@ -293,7 +336,7 @@ "response": [] }, { - "name": "download-generated Copy", + "name": "data download", "protocolProfileBehavior": { "disabledSystemHeaders": { "content-type": true @@ -411,13 +454,13 @@ "response": [] }, { - "name": "project-factory/v1/data/_create Copy", + "name": "data create", "request": { "method": "POST", "header": [ { "key": "authority", - "value": "unified-uat.digit.org" + "value": "unified-dev.digit.org" }, { "key": "accept", @@ -429,19 +472,19 @@ }, { "key": "content-type", - "value": "application/json;charset=UTF-8" + "value": "application/json" }, { "key": "cookie", - "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0; PGADMIN_LANGUAGE=en" + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" }, { "key": "origin", - "value": "https://unified-uat.digit.org" + "value": "https://unified-dev.digit.org" }, { "key": "referer", - "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?id=3a567d66-9de5-4812-9441-240ae6ccb674&draft=true&fetchBoundary=true&key=9&preview=false" + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" }, { "key": "sec-ch-ua", @@ -474,7 +517,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"ResourceDetails\": {\n \"type\": \"boundary\",\n \"hierarchyType\": \"TEST15\",\n \"tenantId\": \"mz\",\n \"fileStoreId\": \"{{fileId}}\",\n \"action\": \"create\",\n // \"campaignId\": \"56cd8661-9d4b-4946-80e9-d50bdcfcce60\",\n \"additionalDetails\": {}\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1052,\n \"uuid\": \"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\n \"userName\": \"UATMZ\",\n \"name\": \"UATMZ\",\n \"mobileNumber\": \"8998988112\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS ADMIN\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1717482930188|en_IN\",\n \"plainAccessRequest\": {}\n}\n}" + "raw": "{\n \"RequestInfo\":{\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"3dcb7be0-fa76-440f-959c-30c7839ca1d0\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1715753883629|en_MZ\",\n \"plainAccessRequest\": {}\n},\n \"ResourceDetails\": {\n \"type\": \"facility\",\n // \"type\": \"facility|user|boundary\",\n \"tenantId\": \"mz\",\n // empty facility\n // \"fileStoreId\": \"cf37fb7a-f07e-44da-9f11-c06841ffdd44\",\n // worng\n // \"fileStoreId\": \"823110ca-55a1-434b-83d4-138e9e262661\",\n // right\n // \"fileStoreId\":\"252e68d4-44f8-4088-814c-ba0046f7da0f\",\n // right user\n // \"fileStoreId\":\"589fc456-70ab-422f-9c9a-b92ea3304f54\",\n //rightt with 5000 rows\n // \"fileStoreId\": \"0b47f2b3-840a-40b5-af8d-2273b836fd79\",\n //rightt with 200 rows\n // \"fileStoreId\":\"078a35f3-6db9-497b-bed5-d58e0ae3800a\",\n \"fileStoreId\":\"ae72d4a2-1a3a-431c-b30a-699983cf9468\",\n \"action\": \"validate\",\n \"hierarchyType\": \"ADMIN\",\n \"additionalDetails\": {}\n }\n}" }, "url": { "raw": "http://localhost:8080/project-factory/v1/data/_create", @@ -494,90 +537,7 @@ "response": [] }, { - "name": "project-factory/v1/project-type/search Copy", - "request": { - "method": "POST", - "header": [ - { - "key": "authority", - "value": "unified-qa.digit.org" - }, - { - "key": "accept", - "value": "application/json, text/plain, */*" - }, - { - "key": "accept-language", - "value": "en-GB,en-US;q=0.9,en;q=0.8" - }, - { - "key": "content-type", - "value": "application/json;charset=UTF-8" - }, - { - "key": "cookie", - "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0" - }, - { - "key": "origin", - "value": "https://unified-qa.digit.org" - }, - { - "key": "referer", - "value": "https://unified-qa.digit.org/workbench-ui/employee/campaign/my-campaign" - }, - { - "key": "sec-ch-ua", - "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" - }, - { - "key": "sec-ch-ua-mobile", - "value": "?0" - }, - { - "key": "sec-ch-ua-platform", - "value": "\"Linux\"" - }, - { - "key": "sec-fetch-dest", - "value": "empty" - }, - { - "key": "sec-fetch-mode", - "value": "cors" - }, - { - "key": "sec-fetch-site", - "value": "same-origin" - }, - { - "key": "user-agent", - "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1716986778045|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"tenantId\": \"mz\",\n \"ids\":[\"{{campaignId}}\"],\n // \"status\": [\n // \"creating\",\n // \"created\"\n // ],\n // \"createdBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n // \"campaignsIncludeDates\": true,\n // \"startDate\": 1716986778045,\n // \"endDate\": 1716986778045,\n // \"campaignName\":\"Performance Test Campaign Jun 17 id 00051\",\n \"pagination\": {\n \"sortBy\": \"createdTime\",\n \"sortOrder\": \"desc\",\n \"limit\": 10,\n \"offset\": 0\n }\n }\n}" - }, - "url": { - "raw": "http://localhost:8080/project-fctory/v1/project-type/search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "project-fctory", - "v1", - "project-type", - "search" - ] - } - }, - "response": [] - }, - { - "name": "project-factory/v1/project-type/search Copy 2", + "name": "data search", "request": { "method": "POST", "header": [ @@ -664,142 +624,10 @@ ] } }, - "response": [ - { - "name": "project-factory/v1/project-type/search Copy", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "authority", - "value": "unified-dev.digit.org" - }, - { - "key": "accept", - "value": "application/json, text/plain, */*" - }, - { - "key": "accept-language", - "value": "en-GB,en-US;q=0.9,en;q=0.8" - }, - { - "key": "content-type", - "value": "application/json" - }, - { - "key": "cookie", - "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" - }, - { - "key": "origin", - "value": "https://unified-dev.digit.org" - }, - { - "key": "referer", - "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" - }, - { - "key": "sec-ch-ua", - "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" - }, - { - "key": "sec-ch-ua-mobile", - "value": "?0" - }, - { - "key": "sec-ch-ua-platform", - "value": "\"Linux\"" - }, - { - "key": "sec-fetch-dest", - "value": "empty" - }, - { - "key": "sec-fetch-mode", - "value": "cors" - }, - { - "key": "sec-fetch-site", - "value": "same-origin" - }, - { - "key": "user-agent", - "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"4d18d41f-bf61-4a50-9382-c7728d57b076\",\n \"userInfo\": {\n \"id\": 947,\n \"uuid\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\",\n \"userName\": \"EMP44\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"HCM SYSTEM ADMINISTRATOR\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"SUPER USER\",\n \"code\": \"SUPERUSER\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"HRMS Admin\",\n \"code\": \"HRMS_ADMIN\",\n \"tenantId\": \"pg\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pg\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1709110250993|en_IN\",\n \"plainAccessRequest\": {}\n },\n \"SearchCriteria\": {\n \"id\": [\n \"fb34e006-0435-4565-acac-988a6992da54\"\n ],\n \"tenantId\": \"mz\",\n \"type\": \"facility\",\n \"status\": \"data-accepted\",\n \"action\": \"create\",\n \"createdBy\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\"\n }\n}" - }, - "url": { - "raw": "http://localhost:8095/project-factory/v1/data/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8095", - "path": [ - "project-factory", - "v1", - "data", - "_search" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "X-Powered-By", - "value": "Express" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "563" - }, - { - "key": "ETag", - "value": "W/\"233-jv57E1Q5Yt5KHhUp7M2vxbi5Abg\"" - }, - { - "key": "Date", - "value": "Tue, 02 Apr 2024 05:35:08 GMT" - }, - { - "key": "Connection", - "value": "keep-alive" - }, - { - "key": "Keep-Alive", - "value": "timeout=5" - } - ], - "cookie": [], - "body": "{\n \"ResponseInfo\": {\n \"apiId\": \"egov-bff\",\n \"ver\": \"0.0.1\",\n \"ts\": 1712036108718,\n \"status\": \"successful\",\n \"desc\": \"new-response\"\n },\n \"ResourceDetails\": [\n {\n \"id\": \"fb34e006-0435-4565-acac-988a6992da54\",\n \"tenantId\": \"mz\",\n \"status\": \"data-accepted\",\n \"action\": \"create\",\n \"fileStoreId\": \"d5a6f652-37da-49a2-9284-e867b9e4de83\",\n \"processedFilestoreId\": \"5f1fcf05-e6d1-47e0-a96f-019a454cc7d2\",\n \"type\": \"facility\",\n \"createdBy\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\",\n \"lastModifiedBy\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\",\n \"createdTime\": 1710921693188,\n \"lastModifiedTime\": 1710921693188,\n \"additionalDetails\": {}\n }\n ]\n}" - } - ] + "response": [] }, { - "name": "/project-factory/v1/project-type/create Copy", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var response=pm.response.json();", - "pm.environment.set(\"campaignId\", response.CampaignDetails.id);", - "pm.environment.set(\"campaignNum\",response.CampaignDetails.campaignNumber)" - ], - "type": "text/javascript", - "packages": {} - } - } - ], + "name": "campaign create", "protocolProfileBehavior": { "disabledSystemHeaders": { "content-type": true @@ -871,16 +699,15 @@ ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1713593588138|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n // \"id\": \"992f8c27-7dde-43f8-9dad-e6ec9d821d39\",\n \"tenantId\": \"mz\",\n // \"status\": \"created\",\n \"action\": \"draft\",\n // \"campaignNumber\": \"CMP-2024-07-30-001374\",\n \"campaignName\": \"jul31_3\",\n \"projectType\": \"LLIN-mz\",\n \"hierarchyType\": \"Health\",\n \"boundaryCode\": \"HEALTH_MO\",\n // \"projectId\": \"baeadf90-ded8-47eb-a02a-c4c9c4527321\",\n \"startDate\": 1722450600000,\n \"endDate\": 1725560999000,\n \"additionalDetails\": {\n \"key\": 10,\n \"beneficiaryType\": \"HOUSEHOLD\"\n },\n \"resources\": [\n {\n \"type\": \"facility\",\n \"filename\": \"Facility Template (56).xlsx\",\n \"resourceId\": \"31a528c6-1345-4587-ad21-7bafcbe3b28f\",\n \"filestoreId\": \"6aebec94-463d-4f81-bb13-5c42ac848c25\",\n \"createResourceId\": \"628b0382-4964-441a-a687-9391b92fa5e5\"\n },\n {\n \"type\": \"boundaryWithTarget\",\n \"filename\": \"Target Template (84).xlsx\",\n \"resourceId\": \"7244300a-dd01-49ca-a39f-27845e84f28c\",\n \"filestoreId\": \"dc3c52ea-96b0-49b4-b38e-6360f09b98e3\"\n },\n {\n \"type\": \"user\",\n \"filename\": \"User Template (30).xlsx\",\n \"resourceId\": \"3fa115c9-a394-48a9-8c53-c9929b0abd0e\",\n \"filestoreId\": \"a0254f2e-1ed0-4255-b471-9a912230eb96\",\n \"createResourceId\": \"ebeaf8e1-e185-4b64-98f1-43b9eb8cc095\"\n }\n ],\n \"boundaries\": [\n {\n \"code\": \"HEALTH_MO\",\n \"type\": \"Country\",\n \"isRoot\": true,\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_NAMPULA\",\n \"type\": \"Province\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_02_CHITIMA-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_02_01_NSADZO\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_01_04_NIHESSIUE\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_03_CHITEEIMA\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_02_CHIFUNDE-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_01_MUALDZI\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n }\n ],\n \"deliveryRules\": [\n {\n \"endDate\": 1723573799000,\n \"products\": [\n {\n \"name\": \"SP 500mg\",\n \"count\": 1,\n \"value\": \"PVAR-2024-03-15-000043\"\n }\n ],\n \"startDate\": 1722537000000,\n \"conditions\": [\n {\n \"value\": 3,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_INDIVIDUAL_LABEL\"\n },\n {\n \"value\": 1.8,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_HOUSEHOLD_LABEL\"\n }\n ],\n \"cycleNumber\": 1,\n \"deliveryNumber\": 1,\n \"deliveryRuleNumber\": 1\n }\n ],\n \"auditDetails\": {\n \"createdBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"lastModifiedBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"createdTime\": 1722324752043,\n \"lastModifiedTime\": 1722324899659\n }\n }\n}" + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"0cc530cb-aeb7-4735-a89b-ed5b0607518d\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1713593588138|en_MZ\",\n \"plainAccessRequest\": {}\n},\n \"CampaignDetails\": {\n // \"id\":\"f9f9b96a-d8aa-427b-a755-25bcc22ef60f\",\n \"hierarchyType\": \"ADMIN\",\n \"tenantId\": \"mz\",\n \"campaignName\": \"testName860\",\n \"action\": \"create\",\n // \"action\": \"create\",\n \"startDate\": 1765497222002,\n \"endDate\": 1767497225002,\n // \"projectId\":\"74c57591-13cc-4e21-97d3-2b6c87e7fc98\",\n \"boundaries\": [\n {\n \"code\": \"f5F6xAskA05\",\n \"type\": \"Provincia\",\n \"isRoot\": false\n },\n {\n \"code\": \"mz\",\n \"type\": \"Country\",\n \"isRoot\": true,\n \"includeAllChildren\": true\n }\n ],\n \"resources\": [\n {\n \"filestoreId\": \"252e68d4-44f8-4088-814c-ba0046f7da0f\",\n \"type\": \"facility\",\n \"filename\": \"hkjsss.xlsx\"\n },\n {\n \"filestoreId\":\"49280d90-31f2-4911-8d1e-0482cc6bf70c\",\n \"type\": \"user\",\n \"filename\": \"hkjsss.xlsx\"\n }\n // {\n // \"filestoreId\": \"d96c0248-dcfd-414c-8f8c-635dad0a89f1\",\n // \"type\": \"boundary\",\n // \"filename\": \"s.xlsx\"\n // }\n ],\n \"projectType\": \"LLIN-mz\",\n \"deliveryRules\": [\n {\n \"startDate\": 1666497225000,\n \"endDate\": 1666497225000,\n \"cycleNumber\": 0,\n \"deliveryNumber\": 0,\n \"deliveryRuleNumber\": 0,\n \"products\": [\n \"string\"\n ],\n \"conditions\": [\n {\n \"attribute\": \"string\",\n \"operator\": \"string\",\n \"value\": 0\n }\n ]\n }\n // {\n // \"startDate\": 1667497225001,\n // \"endDate\": 1668897225001,\n // \"cycleNumber\": 0,\n // \"deliveryNumber\": 0,\n // \"deliveryRuleNumber\": 0,\n // \"products\": [\n // \"string\"\n // ],\n // \"conditions\": [\n // {\n // \"attribute\": \"string\",\n // \"operator\": \"string\",\n // \"value\": 0\n // }\n // ]\n // }\n ],\n \"additionalDetails\": {\n \"beneficiaryType\": \"HOUSEHOLD\"\n }\n }\n}" }, "url": { - "raw": "https://unified-dev.digit.org/project-factory/v1/project-type/create", - "protocol": "https", + "raw": "http://localhost:8080/project-factory/v1/project-type/create", + "protocol": "http", "host": [ - "unified-dev", - "digit", - "org" + "localhost" ], + "port": "8080", "path": [ "project-factory", "v1", @@ -892,7 +719,7 @@ "response": [] }, { - "name": "/project-factory/v1/project-type/update Copy", + "name": "update campaign", "protocolProfileBehavior": { "disabledSystemHeaders": { "content-type": true @@ -965,13 +792,13 @@ ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"44cb5589-8dc2-4182-b5a4-afdb692ce831\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"id\": \"{{campaignId}}\",\n \"tenantId\": \"mz\",\n \"status\": \"drafted\",\n \"action\": \"create\",\n \"campaignNumber\": \"{{campaignNum}}\",\n \"campaignName\": \"{{campaignName}}\",\n \"projectType\": \"LLIN-mz\",\n \"hierarchyType\": \"Health\",\n \"boundaryCode\": \"HEALTH_MO\",\n // \"projectId\": \"baeadf90-ded8-47eb-a02a-c4c9c4527321\",\n \"startDate\": 1722450600000,\n \"endDate\": 1725560999000,\n \"additionalDetails\": {\n \"key\": 10,\n \"beneficiaryType\": \"HOUSEHOLD\"\n },\n \"resources\": [\n {\n \"type\": \"facility\",\n \"filename\": \"Facility Template (56).xlsx\",\n \"resourceId\": \"31a528c6-1345-4587-ad21-7bafcbe3b28f\",\n \"filestoreId\": \"6aebec94-463d-4f81-bb13-5c42ac848c25\",\n \"createResourceId\": \"628b0382-4964-441a-a687-9391b92fa5e5\"\n },\n {\n \"type\": \"boundaryWithTarget\",\n \"filename\": \"Target Template (84).xlsx\",\n \"resourceId\": \"7244300a-dd01-49ca-a39f-27845e84f28c\",\n \"filestoreId\": \"dc3c52ea-96b0-49b4-b38e-6360f09b98e3\"\n },\n {\n \"type\": \"user\",\n \"filename\": \"User Template (30).xlsx\",\n \"resourceId\": \"3fa115c9-a394-48a9-8c53-c9929b0abd0e\",\n \"filestoreId\": \"a0254f2e-1ed0-4255-b471-9a912230eb96\",\n \"createResourceId\": \"ebeaf8e1-e185-4b64-98f1-43b9eb8cc095\"\n }\n ],\n \"boundaries\": [\n {\n \"code\": \"HEALTH_MO\",\n \"type\": \"Country\",\n \"isRoot\": true,\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_NAMPULA\",\n \"type\": \"Province\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_02_CHITIMA-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_02_01_NSADZO\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_01_04_NIHESSIUE\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_03_CHITEEIMA\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_02_CHIFUNDE-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_01_MUALDZI\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n }\n ],\n \"deliveryRules\": [\n {\n \"endDate\": 1723573799000,\n \"products\": [\n {\n \"name\": \"SP 500mg\",\n \"count\": 1,\n \"value\": \"PVAR-2024-03-15-000043\"\n }\n ],\n \"startDate\": 1722537000000,\n \"conditions\": [\n {\n \"value\": 3,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_INDIVIDUAL_LABEL\"\n },\n {\n \"value\": 1.8,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_HOUSEHOLD_LABEL\"\n }\n ],\n \"cycleNumber\": 1,\n \"deliveryNumber\": 1,\n \"deliveryRuleNumber\": 1\n }\n ],\n \"auditDetails\": {\n \"createdBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"lastModifiedBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"createdTime\": 1722324752043,\n \"lastModifiedTime\": 1722324899659\n }\n }\n}" + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"44cb5589-8dc2-4182-b5a4-afdb692ce831\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"id\": \"f9ea7046-75f2-4ac3-837d-caf14fdcdcca\",\n \"tenantId\": \"mz\",\n \"status\": \"drafted\",\n \"action\": \"draft\",\n \"campaignNumber\": \"CMP-2024-05-02-000855\",\n \"campaignName\": \"weartux\",\n \"projectType\": \"MR-DN\",\n \"hierarchyType\": \"ADMIN\",\n \"boundaryCode\": \"\",\n \"projectId\": null,\n \"startDate\": 0,\n \"endDate\": 0,\n \"createdBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"lastModifiedBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"createdTime\": 1714654527543,\n \"lastModifiedTime\": 1714654527544,\n \"additionalDetails\": {\n \"key\": 2,\n \"beneficiaryType\": \"INDIVIDUAL\"\n },\n \"campaignDetails\": {\n \"resources\": []\n }\n }\n}\n// \"boundaries\": [\n// {\n// \"code\": \"f5F6xAskA05\",\n// \"type\": \"Provincia\",\n// \"isRoot\": false\n// },\n// {\n// \"code\": \"mz\",\n// \"type\": \"Country\",\n// \"isRoot\": true,\n// \"includeAllChildren\": true\n// }\n// ]," }, "url": { - "raw": "https://unified-dev.digit.org/project-factory/v1/project-type/update", + "raw": "https://unified-qa.digit.org/project-factory/v1/project-type/update", "protocol": "https", "host": [ - "unified-dev", + "unified-qa", "digit", "org" ], @@ -986,12 +813,7 @@ "response": [] }, { - "name": "getProcessTracks Copy", - "protocolProfileBehavior": { - "disabledSystemHeaders": { - "content-type": true - } - }, + "name": "campaign search", "request": { "method": "POST", "header": [ @@ -1050,39 +872,28 @@ { "key": "user-agent", "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" - }, - { - "key": "Content-Type", - "value": "application/json" } ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1713593588138|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"b2985fc2-9980-4fba-adcf-3248e3a66490\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"ids\": [\n \"7cfc93f2-9c4c-4415-9417-e61d2203bdd8\"\n ],\n \"tenantId\": \"mz\",\n // \"startDate\": 1665497224000,\n // \"endDate\": 1665929226005,\n // \"projectType\": \"default1\",\n // \"campaignName\": \"test1Name803\",\n // \"status\": \"started\",\n // \"createdBy\": \"string\",\n // \"campaignNumber\": \"string\",\n \"pagination\": {\n \"sortBy\": \"createdTime\",\n \"sortOrder\": \"desc\",\n \"limit\": 15,\n \"offset\": 0\n }\n // \"createdTime\":1665929226005\n }\n}" }, "url": { - "raw": "https://unified-dev.digit.org/project-factory/v1/project-type/getProcessTrack?campaignId=eeded5f1-e779-454f-9cc7-2b20ba4839e0", - "protocol": "https", + "raw": "http://localhost:8080/project-factory/v1/project-type/search", + "protocol": "http", "host": [ - "unified-dev", - "digit", - "org" + "localhost" ], + "port": "8080", "path": [ "project-factory", "v1", "project-type", - "getProcessTrack" - ], - "query": [ - { - "key": "campaignId", - "value": "eeded5f1-e779-454f-9cc7-2b20ba4839e0" - } + "search" ] } }, "response": [] } ] -} \ No newline at end of file +} diff --git a/health-services/project-factory/src/server/api/campaignApis.ts b/health-services/project-factory/src/server/api/campaignApis.ts index 4f29fd481a8..f0a5a231965 100644 --- a/health-services/project-factory/src/server/api/campaignApis.ts +++ b/health-services/project-factory/src/server/api/campaignApis.ts @@ -1,58 +1,19 @@ import config from "../config"; -import { v4 as uuidv4 } from "uuid"; +import { v4 as uuidv4 } from 'uuid'; import { httpRequest } from "../utils/request"; import { getFormattedStringForDebug, logger } from "../utils/logger"; -import createAndSearch from "../config/createAndSearch"; -import { - getDataFromSheet, - generateActivityMessage, - throwError, - translateSchema, - replicateRequest, - appendProjectTypeToCapacity, - getLocalizedMessagesHandler, -} from "../utils/genericUtils"; -import { - immediateValidationForTargetSheet, - validateEmptyActive, - validateSheetData, - validateTargetSheetData, - validateViaSchemaSheetWise, -} from "../validators/campaignValidators"; +import createAndSearch from '../config/createAndSearch'; +import { getDataFromSheet, generateActivityMessage, throwError, translateSchema, replicateRequest } from "../utils/genericUtils"; +import { immediateValidationForTargetSheet, validateSheetData, validateTargetSheetData } from '../validators/campaignValidators'; import { callMdmsTypeSchema, getCampaignNumber } from "./genericApis"; -import { - boundaryBulkUpload, - convertToTypeData, - generateHierarchy, - generateProcessedFileAndPersist, - getBoundaryOnWhichWeSplit, - getLocalizedName, - reorderBoundariesOfDataAndValidate, - checkIfSourceIsMicroplan, - createIdRequests, - createUniqueUserNameViaIdGen, - boundaryGeometryManagement, -} from "../utils/campaignUtils"; -const _ = require("lodash"); -import { produceModifiedMessages } from "../kafka/Producer"; +import { boundaryBulkUpload, convertToTypeData, generateHierarchy, generateProcessedFileAndPersist, getLocalizedName, reorderBoundariesOfDataAndValidate } from "../utils/campaignUtils"; +const _ = require('lodash'); +import { produceModifiedMessages } from "../kafka/Listener"; import { createDataService } from "../service/dataManageService"; import { searchProjectTypeCampaignService } from "../service/campaignManageService"; import { getExcelWorkbookFromFileURL } from "../utils/excelUtils"; -import { - processTrackStatuses, - processTrackTypes, - resourceDataStatuses, -} from "../config/constants"; -import { persistTrack } from "../utils/processTrackUtils"; -import { checkAndGiveIfParentCampaignAvailable } from "../utils/onGoingCampaignUpdateUtils"; -import { validateMicroplanFacility } from "../validators/microplanValidators"; -import { - createPlanFacilityForMicroplan, - updateFacilityDetailsForMicroplan, -} from "../utils/microplanUtils"; -import { getTransformedLocale } from "../utils/localisationUtils"; -import { BoundaryModels } from "../models"; -import { searchBoundaryRelationshipDefinition } from "./coreApis"; + + /** * Enriches the campaign data with unique IDs and generates campaign numbers. @@ -62,30 +23,15 @@ async function enrichCampaign(requestBody: any) { // Enrich campaign data with unique IDs and generate campaign numbers if (requestBody?.Campaign) { requestBody.Campaign.id = uuidv4(); - logger.info(`ENRICHMENT:: generated id for the campaign ${requestBody.Campaign.id}`); - requestBody.Campaign.campaignNo = await getCampaignNumber( - requestBody, - config.values.idgen.format, - config.values.idgen.idName, - requestBody?.Campaign?.tenantId - ); - logger.info(`ENRICHMENT:: generated sequence no for the campaign ${requestBody.Campaign.campaignNo}`); + requestBody.Campaign.campaignNo = await getCampaignNumber(requestBody, config.values.idgen.format, config.values.idgen.idName, requestBody?.Campaign?.tenantId); for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { campaignDetails.id = uuidv4(); } } } -async function getAllFacilitiesInLoop( - searchedFacilities: any[], - facilitySearchParams: any, - facilitySearchBody: any -) { - const response = await httpRequest( - config.host.facilityHost + config.paths.facilitySearch, - facilitySearchBody, - facilitySearchParams - ); +async function getAllFacilitiesInLoop(searchedFacilities: any[], facilitySearchParams: any, facilitySearchBody: any) { + const response = await httpRequest(config.host.facilityHost + config.paths.facilitySearch, facilitySearchBody, facilitySearchParams); if (Array.isArray(response?.Facilities)) { searchedFacilities.push(...response?.Facilities); @@ -106,24 +52,20 @@ async function getAllFacilities(tenantId: string, requestBody: any) { // Retrieve all facilities for the given tenant ID const facilitySearchBody = { RequestInfo: requestBody?.RequestInfo, - Facility: { isPermanent: true }, + Facility: { isPermanent: true } }; const facilitySearchParams = { limit: 50, offset: 0, - tenantId: tenantId?.split(".")?.[0], + tenantId: tenantId?.split('.')?.[0] }; const searchedFacilities: any[] = []; let searchAgain = true; while (searchAgain) { - searchAgain = await getAllFacilitiesInLoop( - searchedFacilities, - facilitySearchParams, - facilitySearchBody - ); + searchAgain = await getAllFacilitiesInLoop(searchedFacilities, facilitySearchParams, facilitySearchBody); facilitySearchParams.offset += 50; } @@ -137,21 +79,17 @@ async function getAllFacilities(tenantId: string, requestBody: any) { * @param requestBody The request body containing additional parameters. * @returns An array of facilities. */ -async function getFacilitiesViaIds( - tenantId: string, - ids: any[], - requestBody: any -) { +async function getFacilitiesViaIds(tenantId: string, ids: any[], requestBody: any) { // Retrieve facilities by their IDs const facilitySearchBody: any = { RequestInfo: requestBody?.RequestInfo, - Facility: {}, + Facility: {} }; const facilitySearchParams = { limit: 50, offset: 0, - tenantId: tenantId?.split(".")?.[0], + tenantId: tenantId?.split('.')?.[0] }; const searchedFacilities: any[] = []; @@ -160,11 +98,7 @@ async function getFacilitiesViaIds( for (let i = 0; i < ids.length; i += 50) { const chunkIds = ids.slice(i, i + 50); facilitySearchBody.Facility.id = chunkIds; - await getAllFacilitiesInLoop( - searchedFacilities, - facilitySearchParams, - facilitySearchBody - ); + await getAllFacilitiesInLoop(searchedFacilities, facilitySearchParams, facilitySearchBody); } return searchedFacilities; @@ -186,16 +120,13 @@ function getParamsViaElements(elements: any, request: any) { if (element?.isInParams) { if (element?.value) { _.set(params, element?.keyPath, element?.value); - } else if (element?.getValueViaPath) { - _.set( - params, - element?.keyPath, - _.get(request.body, element?.getValueViaPath) - ); + } + else if (element?.getValueViaPath) { + _.set(params, element?.keyPath, _.get(request.body, element?.getValueViaPath)) } } } - return params; + return params } /** @@ -212,14 +143,12 @@ function changeBodyViaElements(elements: any, requestBody: any) { if (element?.isInBody) { if (element?.value) { _.set(requestBody, element?.keyPath, element?.value); - } else if (element?.getValueViaPath) { - _.set( - requestBody, - element?.keyPath, - _.get(requestBody, element?.getValueViaPath) - ); - } else { - _.set(requestBody, element?.keyPath, {}); + } + else if (element?.getValueViaPath) { + _.set(requestBody, element?.keyPath, _.get(requestBody, element?.getValueViaPath)) + } + else { + _.set(requestBody, element?.keyPath, {}) } } } @@ -240,255 +169,122 @@ function changeBodyViaElements(elements: any, requestBody: any) { // } // } -function updateErrorsForUser( - request: any, - newCreatedData: any[], - newSearchedData: any[], - errors: any[], - createAndSearchConfig: any, - userNameAndPassword: any[] -) { - const isSourceMicroplan = - request?.body?.ResourceDetails?.additionalDetails?.source == "microplan"; +function updateErrorsForUser(newCreatedData: any[], newSearchedData: any[], errors: any[], createAndSearchConfig: any, userNameAndPassword: any[]) { newCreatedData.forEach((createdElement: any) => { let foundMatch = false; for (const searchedElement of newSearchedData) { if (searchedElement?.code === createdElement?.code) { foundMatch = true; newSearchedData.splice(newSearchedData.indexOf(searchedElement), 1); - errors.push({ - status: "CREATED", - rowNumber: createdElement["!row#number!"], - isUniqueIdentifier: isSourceMicroplan ? false : true, - uniqueIdentifier: _.get( - searchedElement, - createAndSearchConfig.uniqueIdentifier, - "" - ), - errorDetails: "", - }); + errors.push({ status: "CREATED", rowNumber: createdElement["!row#number!"], isUniqueIdentifier: true, uniqueIdentifier: _.get(searchedElement, createAndSearchConfig.uniqueIdentifier, ""), errorDetails: "" }) userNameAndPassword.push({ userName: searchedElement?.user?.userName, password: createdElement?.user?.password, - rowNumber: createdElement["!row#number!"], - }); + rowNumber: createdElement["!row#number!"] + }) break; } } if (!foundMatch) { - errors.push({ - status: "NOT_CREATED", - rowNumber: createdElement["!row#number!"], - errorDetails: `Can't confirm creation of this data`, - }); - logger.info( - "Can't confirm creation of this data of row number : " + - createdElement["!row#number!"] - ); + errors.push({ status: "NOT_CREATED", rowNumber: createdElement["!row#number!"], errorDetails: `Can't confirm creation of this data` }) + logger.info("Can't confirm creation of this data of row number : " + createdElement["!row#number!"]); } }); } -function updateErrors( - newCreatedData: any[], - newSearchedData: any[], - errors: any[], - createAndSearchConfig: any -) { +function updateErrors(newCreatedData: any[], newSearchedData: any[], errors: any[], createAndSearchConfig: any) { newCreatedData.forEach((createdElement: any) => { let foundMatch = false; for (const searchedElement of newSearchedData) { let match = true; for (const key in createdElement) { - if ( - createdElement[key] !== searchedElement[key] && - key != "!row#number!" - ) { + if (createdElement[key] !== searchedElement[key] && key != '!row#number!') { match = false; break; } } if (match) { foundMatch = true; - createdElement.id = searchedElement.id; newSearchedData.splice(newSearchedData.indexOf(searchedElement), 1); - errors.push({ - status: "CREATED", - rowNumber: createdElement["!row#number!"], - isUniqueIdentifier: true, - uniqueIdentifier: _.get( - searchedElement, - createAndSearchConfig.uniqueIdentifier, - "" - ), - errorDetails: "", - }); + errors.push({ status: "CREATED", rowNumber: createdElement["!row#number!"], isUniqueIdentifier: true, uniqueIdentifier: _.get(searchedElement, createAndSearchConfig.uniqueIdentifier, ""), errorDetails: "" }) break; } } if (!foundMatch) { - errors.push({ - status: "NOT_CREATED", - rowNumber: createdElement["!row#number!"], - errorDetails: `Can't confirm creation of this data`, - }); - logger.info( - "Can't confirm creation of this data of row number : " + - createdElement["!row#number!"] - ); + errors.push({ status: "NOT_CREATED", rowNumber: createdElement["!row#number!"], errorDetails: `Can't confirm creation of this data` }) + logger.info("Can't confirm creation of this data of row number : " + createdElement["!row#number!"]); } }); } -function matchCreatedAndSearchedData( - createdData: any[], - searchedData: any[], - request: any, - createAndSearchConfig: any, - activities: any -) { + +function matchCreatedAndSearchedData(createdData: any[], searchedData: any[], request: any, createAndSearchConfig: any, activities: any) { const newCreatedData = JSON.parse(JSON.stringify(createdData)); const newSearchedData = JSON.parse(JSON.stringify(searchedData)); const uid = createAndSearchConfig.uniqueIdentifier; newCreatedData.forEach((element: any) => { delete element[uid]; - }); - var errors: any[] = []; + }) + var errors: any[] = [] if (request?.body?.ResourceDetails?.type != "user") { if (request?.body?.ResourceDetails?.type == "facility") { newCreatedData?.forEach((element: any) => { - delete element.address; - }); + delete element.address + }) } - updateErrors( - newCreatedData, - newSearchedData, - errors, - createAndSearchConfig - ); - updateFacilityDetailsForMicroplan(request, newCreatedData); - } else { - var userNameAndPassword: any = []; - updateErrorsForUser( - request, - newCreatedData, - newSearchedData, - errors, - createAndSearchConfig, - userNameAndPassword - ); - request.body.userNameAndPassword = userNameAndPassword; + updateErrors(newCreatedData, newSearchedData, errors, createAndSearchConfig); + } + else { + var userNameAndPassword: any = [] + updateErrorsForUser(newCreatedData, newSearchedData, errors, createAndSearchConfig, userNameAndPassword); + request.body.userNameAndPassword = userNameAndPassword } - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails - ? [...request?.body?.sheetErrorDetails, ...errors] - : errors; - request.body.Activities = activities; + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + request.body.Activities = activities } -async function getUuidsError( - request: any, - response: any, - mobileNumberRowNumberMapping: any -) { - var errors: any[] = []; +async function getUuidsError(request: any, response: any, mobileNumberRowNumberMapping: any) { + var errors: any[] = [] var count = 0; - request.body.mobileNumberUuidsMapping = request.body.mobileNumberUuidsMapping - ? request.body.mobileNumberUuidsMapping - : {}; + request.body.mobileNumberUuidsMapping = request.body.mobileNumberUuidsMapping ? request.body.mobileNumberUuidsMapping : {}; for (const user of response.Individual) { if (!user?.userUuid) { - logger.info( - `User with mobileNumber ${user?.mobileNumber} doesn't have userUuid` - ); - errors.push({ - status: "INVALID", - rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], - errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userUuid`, - }); + logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have userUuid`) + errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userUuid` }) count++; - } else if (!user?.userDetails?.username) { - logger.info( - `User with mobileNumber ${user?.mobileNumber} doesn't have username` - ); - errors.push({ - status: "INVALID", - rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], - errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have username`, - }); - count++; - } else if (!user?.userDetails?.password) { - logger.info( - `User with mobileNumber ${user?.mobileNumber} doesn't have password` - ); - errors.push({ - status: "INVALID", - rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], - errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have password`, - }); - count++; - } else if (!user?.userUuid) { - logger.info( - `User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid` - ); - errors.push({ - status: "INVALID", - rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], - errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid`, - }); + } + else if (!user?.userDetails?.username) { + logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have username`) + errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have username` }) count++; - } else { - request.body.mobileNumberUuidsMapping[user?.mobileNumber] = { - userUuid: user?.id, - code: user?.userDetails?.username, - rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], - password: user?.userDetails?.password, - userServiceUuid: user?.userUuid, - }; + } + else { + request.body.mobileNumberUuidsMapping[user?.mobileNumber] = { userUuid: user?.id, code: user?.userDetails?.username, rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber] } } } if (count > 0) { - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails - ? [...request?.body?.sheetErrorDetails, ...errors] - : errors; + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; } } -const createBatchRequest = async ( - request: any, - batch: any[], - mobileNumberRowNumberMapping: any -) => { +const createBatchRequest = async (request: any, batch: any[], mobileNumberRowNumberMapping: any) => { const searchBody = { RequestInfo: request?.body?.RequestInfo, Individual: { - mobileNumber: batch, - }, + mobileNumber: batch + } }; const params = { limit: 55, offset: 0, tenantId: request?.body?.ResourceDetails?.tenantId, - includeDeleted: true, + includeDeleted: true }; logger.info("Individual search to validate the mobile no initiated"); - const response = await httpRequest( - config.host.healthIndividualHost + config.paths.healthIndividualSearch, - searchBody, - params, - undefined, - undefined, - undefined, - undefined, - true - ); + const response = await httpRequest(config.host.healthIndividualHost + config.paths.healthIndividualSearch, searchBody, params, undefined, undefined, undefined, undefined, true); if (!response) { - throwError( - "COMMON", - 400, - "INTERNAL_SERVER_ERROR", - "Error occurred during user search while validating mobile number." - ); + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Error occurred during user search while validating mobile number."); } if (config.values.notCreateUserIfAlreadyThere) { await getUuidsError(request, response, mobileNumberRowNumberMapping); @@ -500,14 +296,8 @@ const createBatchRequest = async ( return []; }; -async function getUserWithMobileNumbers( - request: any, - mobileNumbers: any[], - mobileNumberRowNumberMapping: any -) { - logger.debug( - "mobileNumbers to search: " + getFormattedStringForDebug(mobileNumbers) - ); +async function getUserWithMobileNumbers(request: any, mobileNumbers: any[], mobileNumberRowNumberMapping: any) { + logger.info("mobileNumbers to search: " + JSON.stringify(mobileNumbers)); const BATCH_SIZE = 50; let allResults: any[] = []; @@ -515,9 +305,7 @@ async function getUserWithMobileNumbers( const batchPromises = []; for (let i = 0; i < mobileNumbers.length; i += BATCH_SIZE) { const batch = mobileNumbers.slice(i, i + BATCH_SIZE); - batchPromises.push( - createBatchRequest(request, batch, mobileNumberRowNumberMapping) - ); + batchPromises.push(createBatchRequest(request, batch, mobileNumberRowNumberMapping)); } // Wait for all batch requests to complete @@ -533,179 +321,87 @@ async function getUserWithMobileNumbers( return resultSet; } + async function matchUserValidation(createdData: any[], request: any) { var count = 0; - const errors = []; - const mobileNumbers = createdData - .filter((item) => item?.user?.mobileNumber) - .map((item) => item?.user?.mobileNumber); + const errors = [] + const mobileNumbers = createdData.filter(item => item?.user?.mobileNumber).map(item => (item?.user?.mobileNumber)); const mobileNumberRowNumberMapping = createdData.reduce((acc, curr) => { acc[curr.user.mobileNumber] = curr["!row#number!"]; return acc; }, {}); - logger.debug( - "mobileNumberRowNumberMapping : " + - getFormattedStringForDebug(mobileNumberRowNumberMapping) - ); - const mobileNumberResponse = await getUserWithMobileNumbers( - request, - mobileNumbers, - mobileNumberRowNumberMapping - ); + logger.info("mobileNumberRowNumberMapping : " + JSON.stringify(mobileNumberRowNumberMapping)); + const mobileNumberResponse = await getUserWithMobileNumbers(request, mobileNumbers, mobileNumberRowNumberMapping); for (const key in mobileNumberRowNumberMapping) { - if ( - mobileNumberResponse.has(key) && - !config.values.notCreateUserIfAlreadyThere - ) { - if (Array.isArray(mobileNumberRowNumberMapping[key])) { - for (const row of mobileNumberRowNumberMapping[key]) { - errors.push({ - status: "INVALID", - rowNumber: row.row, - sheetName: row.sheetName, - errorDetails: `User with contact number ${key} already exists`, - }); - } - } else { - errors.push({ - status: "INVALID", - rowNumber: mobileNumberRowNumberMapping[key], - errorDetails: `User with contact number ${key} already exists`, - }); - } + if (mobileNumberResponse.has(key) && !config.values.notCreateUserIfAlreadyThere) { + errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[key], errorDetails: `User with mobileNumber ${key} already exists` }) count++; } } if (count) { - request.body.ResourceDetails.status = "invalid"; + request.body.ResourceDetails.status = "invalid" } logger.info("Invalid resources count : " + count); - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails - ? [...request?.body?.sheetErrorDetails, ...errors] - : errors; + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; } -function matchViaUserIdAndCreationTime( - createdData: any[], - searchedData: any[], - request: any, - creationTime: any, - createAndSearchConfig: any, - activities: any -) { +function matchViaUserIdAndCreationTime(createdData: any[], searchedData: any[], request: any, creationTime: any, createAndSearchConfig: any, activities: any) { var matchingSearchData = []; - const userUuid = request?.body?.RequestInfo?.userInfo?.uuid; + const userUuid = request?.body?.RequestInfo?.userInfo?.uuid var count = 0; if (request?.body?.ResourceDetails?.type != "user") { for (const data of searchedData) { - if ( - data?.auditDetails?.createdBy == userUuid && - data?.auditDetails?.createdTime >= creationTime - ) { + if (data?.auditDetails?.createdBy == userUuid && data?.auditDetails?.createdTime >= creationTime) { matchingSearchData.push(data); count++; } } - } else { + } + else { count = searchedData.length; matchingSearchData = searchedData; } if (count < createdData.length) { - request.body.ResourceDetails.status = "PERSISTER_ERROR"; + request.body.ResourceDetails.status = "PERSISTER_ERROR" } - matchCreatedAndSearchedData( - createdData, - matchingSearchData, - request, - createAndSearchConfig, - activities - ); + matchCreatedAndSearchedData(createdData, matchingSearchData, request, createAndSearchConfig, activities); logger.info("New created resources count : " + count); } -async function processSearch( - createAndSearchConfig: any, - request: any, - params: any -) { +async function processSearch(createAndSearchConfig: any, request: any, params: any) { setSearchLimits(createAndSearchConfig, request, params); - const arraysToMatch = await performSearch( - createAndSearchConfig, - request, - params - ); + const arraysToMatch = await performSearch(createAndSearchConfig, request, params); return arraysToMatch; } -function setSearchLimits( - createAndSearchConfig: any, - request: any, - params: any -) { - setLimitOrOffset( - createAndSearchConfig?.searchDetails?.searchLimit, - params, - request.body - ); - setLimitOrOffset( - createAndSearchConfig?.searchDetails?.searchOffset, - params, - request.body - ); +function setSearchLimits(createAndSearchConfig: any, request: any, params: any) { + setLimitOrOffset(createAndSearchConfig?.searchDetails?.searchLimit, params, request.body); + setLimitOrOffset(createAndSearchConfig?.searchDetails?.searchOffset, params, request.body); } -function setLimitOrOffset( - limitOrOffsetConfig: any, - params: any, - requestBody: any -) { +function setLimitOrOffset(limitOrOffsetConfig: any, params: any, requestBody: any) { if (limitOrOffsetConfig) { if (limitOrOffsetConfig?.isInParams) { - _.set( - params, - limitOrOffsetConfig?.keyPath, - parseInt(limitOrOffsetConfig?.value) - ); + _.set(params, limitOrOffsetConfig?.keyPath, parseInt(limitOrOffsetConfig?.value)); } if (limitOrOffsetConfig?.isInBody) { - _.set( - requestBody, - limitOrOffsetConfig?.keyPath, - parseInt(limitOrOffsetConfig?.value) - ); + _.set(requestBody, limitOrOffsetConfig?.keyPath, parseInt(limitOrOffsetConfig?.value)); } } } -async function performSearch( - createAndSearchConfig: any, - request: any, - params: any -) { +async function performSearch(createAndSearchConfig: any, request: any, params: any) { const arraysToMatch: any[] = []; let searchAgain = true; while (searchAgain) { const searcRequestBody = { - RequestInfo: request?.body?.RequestInfo, - }; - changeBodyViaElements( - createAndSearchConfig?.searchDetails?.searchElements, - searcRequestBody - ); - const response = await httpRequest( - createAndSearchConfig?.searchDetails?.url, - searcRequestBody, - params - ); - const resultArray = _.get( - response, - createAndSearchConfig?.searchDetails?.searchPath - ); + RequestInfo: request?.body?.RequestInfo + } + changeBodyViaElements(createAndSearchConfig?.searchDetails?.searchElements, searcRequestBody) + const response = await httpRequest(createAndSearchConfig?.searchDetails?.url, searcRequestBody, params); + const resultArray = _.get(response, createAndSearchConfig?.searchDetails?.searchPath); if (resultArray && Array.isArray(resultArray)) { arraysToMatch.push(...resultArray); - if ( - resultArray.length < - parseInt(createAndSearchConfig?.searchDetails?.searchLimit?.value) - ) { + if (resultArray.length < parseInt(createAndSearchConfig?.searchDetails?.searchLimit?.value)) { searchAgain = false; } } else { @@ -716,32 +412,21 @@ async function performSearch( return arraysToMatch; } -function updateOffset( - createAndSearchConfig: any, - params: any, - requestBody: any -) { - const offsetConfig = createAndSearchConfig?.searchDetails?.searchOffset; - const limit = createAndSearchConfig?.searchDetails?.searchLimit?.value; +function updateOffset(createAndSearchConfig: any, params: any, requestBody: any) { + const offsetConfig = createAndSearchConfig?.searchDetails?.searchOffset + const limit = createAndSearchConfig?.searchDetails?.searchLimit?.value if (offsetConfig) { if (offsetConfig?.isInParams) { - _.set( - params, - offsetConfig?.keyPath, - parseInt(_.get(params, offsetConfig?.keyPath) + parseInt(limit)) - ); + _.set(params, offsetConfig?.keyPath, parseInt(_.get(params, offsetConfig?.keyPath) + parseInt(limit))); } if (offsetConfig?.isInBody) { - _.set( - requestBody, - offsetConfig?.keyPath, - parseInt(_.get(requestBody, offsetConfig?.keyPath) + parseInt(limit)) - ); + _.set(requestBody, offsetConfig?.keyPath, parseInt(_.get(requestBody, offsetConfig?.keyPath) + parseInt(limit))); } } } -async function processSearchAndValidation(request: any) { + +async function processSearchAndValidation(request: any, createAndSearchConfig: any, dataFromSheet: any[]) { // if (request?.body?.dataToSearch?.length > 0) { // const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request); // changeBodyViaElements(createAndSearchConfig?.searchDetails?.searchElements, request) @@ -750,45 +435,36 @@ async function processSearchAndValidation(request: any) { // matchData(request, request.body.dataToSearch, arraysToMatch, createAndSearchConfig) // } if (request?.body?.ResourceDetails?.type == "user") { - await enrichEmployees(request?.body?.dataToCreate, request); - await matchUserValidation(request.body.dataToCreate, request); + await enrichEmployees(request?.body?.dataToCreate, request) + await matchUserValidation(request.body.dataToCreate, request) } } async function getEmployeesBasedOnUuids(dataToCreate: any[], request: any) { const searchBody = { - RequestInfo: request?.body?.RequestInfo, + RequestInfo: request?.body?.RequestInfo }; const tenantId = request?.body?.ResourceDetails?.tenantId; const searchUrl = config.host.hrmsHost + config.paths.hrmsEmployeeSearch; logger.info(`Waiting for 10 seconds`); - await new Promise((resolve) => setTimeout(resolve, 10000)); + await new Promise(resolve => setTimeout(resolve, 10000)); const chunkSize = 50; let employeesSearched: any[] = []; for (let i = 0; i < dataToCreate.length; i += chunkSize) { const chunk = dataToCreate.slice(i, i + chunkSize); - const uuids = chunk.map((data: any) => data.uuid).join(","); + const uuids = chunk.map((data: any) => data.uuid).join(','); const params = { tenantId: tenantId, uuids: uuids, limit: 51, - offset: 0, + offset: 0 }; try { - const response = await httpRequest( - searchUrl, - searchBody, - params, - undefined, - undefined, - undefined, - undefined, - true - ); + const response = await httpRequest(searchUrl, searchBody, params, undefined, undefined, undefined, undefined, true); if (response && response.Employees) { employeesSearched = employeesSearched.concat(response.Employees); } else { @@ -796,311 +472,104 @@ async function getEmployeesBasedOnUuids(dataToCreate: any[], request: any) { } } catch (error: any) { console.log(error); - throwError( - "COMMON", - 500, - "INTERNAL_SERVER_ERROR", - error.message || - "Some internal error occurred while searching employees" - ); + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", error.message || "Some internal error occurred while searching employees"); } } return employeesSearched; } + + + + + // Confirms the creation of resources by matching created and searched data. -async function confirmCreation( - createAndSearchConfig: any, - request: any, - dataToCreate: any[], - creationTime: any, - activities: any -) { +async function confirmCreation(createAndSearchConfig: any, request: any, dataToCreate: any[], creationTime: any, activities: any) { // Confirm creation of resources by matching data // wait for 5 seconds if (request?.body?.ResourceDetails?.type != "user") { - const params: any = getParamsViaElements( - createAndSearchConfig?.searchDetails?.searchElements, - request - ); - const arraysToMatch = await processSearch( - createAndSearchConfig, - request, - params - ); - matchViaUserIdAndCreationTime( - dataToCreate, - arraysToMatch, - request, - creationTime, - createAndSearchConfig, - activities - ); - } else { - const arraysToMatch = await getEmployeesBasedOnUuids(dataToCreate, request); - matchViaUserIdAndCreationTime( - dataToCreate, - arraysToMatch, - request, - creationTime, - createAndSearchConfig, - activities - ); + const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request); + const arraysToMatch = await processSearch(createAndSearchConfig, request, params) + matchViaUserIdAndCreationTime(dataToCreate, arraysToMatch, request, creationTime, createAndSearchConfig, activities) + } + else { + const arraysToMatch = await getEmployeesBasedOnUuids(dataToCreate, request) + matchViaUserIdAndCreationTime(dataToCreate, arraysToMatch, request, creationTime, createAndSearchConfig, activities) } } -async function processValidateAfterSchema( - dataFromSheet: any, - request: any, - createAndSearchConfig: any, - localizationMap?: { [key: string]: string } -) { +async function processValidateAfterSchema(dataFromSheet: any, request: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { try { - validateEmptyActive(dataFromSheet, request?.body?.ResourceDetails?.type, localizationMap); - if ( - request?.body?.ResourceDetails?.additionalDetails?.source == - "microplan" && - request?.body?.ResourceDetails?.type == "facility" - ) { - validateMicroplanFacility(request, dataFromSheet, localizationMap); - } - const typeData = await convertToTypeData( - request, - dataFromSheet, - createAndSearchConfig, - request.body, - localizationMap - ); + const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) request.body.dataToSearch = typeData.searchData; request.body.dataToCreate = typeData.createData; - await processSearchAndValidation(request); - await reorderBoundariesOfDataAndValidate(request, localizationMap); + await processSearchAndValidation(request, createAndSearchConfig, dataFromSheet) + await reorderBoundariesOfDataAndValidate(request, localizationMap) await generateProcessedFileAndPersist(request, localizationMap); } catch (error) { - console.log(error); + console.log(error) await handleResouceDetailsError(request, error); } } -export async function processValidateAfterSchemaSheetWise( - request: any, - createAndSearchConfig: any, - localizationMap?: { [key: string]: string } -) { - if ( - request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" && - request.body.ResourceDetails.type == "user" - ) { - await generateProcessedFileAndPersist(request, localizationMap); - } -} - -async function processSheetWise( - forCreate: any, - dataFromSheet: any, - request: any, - createAndSearchConfig: any, - translatedSchema: any, - localizationMap?: { [key: string]: string } -) { - try { - const errorMap: any = await validateViaSchemaSheetWise( - dataFromSheet, - translatedSchema, - request, - localizationMap - ); - enrichErrorIfSheetInvalid(request, errorMap); - await processSearchAndValidation(request); - if (request?.body?.sheetErrorDetails?.length > 0) { - request.body.ResourceDetails.status = resourceDataStatuses.invalid; - await generateProcessedFileAndPersist(request, localizationMap); - } else { - if (forCreate) { - await processAfterValidation( - dataFromSheet, - createAndSearchConfig, - request, - localizationMap - ); - } else { - await processValidateAfterSchemaSheetWise( - request, - createAndSearchConfig, - localizationMap - ); - } - } - } catch (error) { - console.log(error); - await handleResouceDetailsError(request, error); - } -} - -function enrichErrorIfSheetInvalid(request: any, errorMap: any) { - if (Object.keys(errorMap).length > 0) { - var sheetErrorDetails = []; - for (const sheetName of Object.keys(errorMap)) { - const errorData = errorMap[sheetName]; - for (const row of Object.keys(errorData)) { - if (errorData[row].length > 0) { - const errorDetails = errorData[row].join(", "); - sheetErrorDetails.push({ - status: "INVALID", - sheetName: sheetName, - rowNumber: row, - errorDetails: errorDetails, - }); - } - } - } - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails - ? [...request?.body?.sheetErrorDetails, ...sheetErrorDetails] - : sheetErrorDetails; - } -} - -async function processValidate( - request: any, - localizationMap?: { [key: string]: string } -) { +async function processValidate(request: any, localizationMap?: { [key: string]: string }) { const type: string = request.body.ResourceDetails.type; const tenantId = request.body.ResourceDetails.tenantId; - const createAndSearchConfig = createAndSearch[type]; - const dataFromSheet: any = await getDataFromSheet( - request, - request?.body?.ResourceDetails?.fileStoreId, - request?.body?.ResourceDetails?.tenantId, - createAndSearchConfig, - null, - localizationMap - ); - if (type == "boundaryWithTarget") { - const hierarchyType = request?.body?.ResourceDetails?.hierarchyType; - const hierarchyModule = `${config.localisation.boundaryPrefix - }-${getTransformedLocale(hierarchyType)}`?.toLowerCase(); - const localizationMapForHierarchy = await getLocalizedMessagesHandler( - request, - request?.body?.ResourceDetails?.tenantId, - hierarchyModule - ); - localizationMap = { - ...localizationMap, - ...localizationMapForHierarchy, - }; - let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request, request?.body?.ResourceDetails?.tenantId); - differentTabsBasedOnLevel = getLocalizedName( - `${request?.body?.ResourceDetails?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), - localizationMap - ); + const createAndSearchConfig = createAndSearch[type] + const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, null, localizationMap) + if (type == 'boundaryWithTarget') { logger.info("target sheet format validation started"); - await immediateValidationForTargetSheet( - request, - dataFromSheet, - differentTabsBasedOnLevel, - localizationMap - ); - logger.info( - "target sheet format validation completed and starts with data validation" - ); - validateTargetSheetData( - dataFromSheet, - request, - createAndSearchConfig?.boundaryValidation, - differentTabsBasedOnLevel, - localizationMap - ); - } else { + // added await to ensure validations complete before proceeding, preventing premature errors. + await immediateValidationForTargetSheet(dataFromSheet, localizationMap); + logger.info("target sheet format validation completed and starts with data validation"); + validateTargetSheetData(dataFromSheet, request, createAndSearchConfig?.boundaryValidation, localizationMap); + } + + else { let schema: any; if (type == "facility" || type == "user") { - const isUpdate = request?.body?.parentCampaignObject ? true : false; - if ( - request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" - ) { - schema = await callMdmsTypeSchema( - request, - tenantId, - isUpdate, - type, - "microplan" - ); - } else { - schema = await callMdmsTypeSchema(request, tenantId, isUpdate, type); - } + const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); + schema = mdmsResponse } const translatedSchema = await translateSchema(schema, localizationMap); - if (Array.isArray(dataFromSheet)) { - if ( - request?.body?.ResourceDetails?.additionalDetails?.source != "microplan" - ) { - await validateSheetData( - dataFromSheet, - request, - translatedSchema, - createAndSearchConfig?.boundaryValidation, - localizationMap - ); - } - processValidateAfterSchema( - dataFromSheet, - request, - createAndSearchConfig, - localizationMap - ); - } else { - if (dataFromSheet && Object.keys(dataFromSheet).length > 0) { - processSheetWise( - false, - dataFromSheet, - request, - createAndSearchConfig, - translatedSchema, - localizationMap - ); - } else { - throwError( - "COMMON", - 400, - "VALIDATION_ERROR", - "No data filled in the sheet." - ); - } - } + await validateSheetData(dataFromSheet, request, translatedSchema, createAndSearchConfig?.boundaryValidation, localizationMap) + processValidateAfterSchema(dataFromSheet, request, createAndSearchConfig, localizationMap) } } function convertUserRoles(employees: any[], request: any) { for (const employee of employees) { if (employee?.user?.roles) { - var newRoles: any[] = []; - if (!Array.isArray(employee.user.roles)) { - const rolesArray = employee.user.roles - .split(",") - .map((role: any) => role.trim()); - for (const role of rolesArray) { - const code = role.toUpperCase().split(" ").join("_"); - newRoles.push({ - name: role, - code: code, - tenantId: request?.body?.ResourceDetails?.tenantId, - }); - } - employee.user.roles = newRoles; + var newRoles: any[] = [] + const rolesArray = employee.user.roles.split(',').map((role: any) => role.trim()); + for (const role of rolesArray) { + const code = role.toUpperCase().split(' ').join('_') + newRoles.push({ name: role, code: code, tenantId: request?.body?.ResourceDetails?.tenantId }) } + employee.user.roles = newRoles } } } +function generateHash(input: string): string { + const prime = 31; // Prime number + let hash = 0; + for (let i = 0; i < input.length; i++) { + hash = (hash * prime + input.charCodeAt(i)) % 100000; // Limit hash to 5 digits + } + return hash.toString().padStart(6, '0'); +} + function generateUserPassword() { // Function to generate a random lowercase letter function getRandomLowercaseLetter() { - const letters = "abcdefghijklmnopqrstuvwxyz"; + const letters = 'abcdefghijklmnopqrstuvwxyz'; return letters.charAt(Math.floor(Math.random() * letters.length)); } // Function to generate a random uppercase letter function getRandomUppercaseLetter() { - const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; return letters.charAt(Math.floor(Math.random() * letters.length)); } @@ -1125,6 +594,20 @@ function generateUserPassword() { return `${firstSequence}@${randomNumber}`; } + +function enrichUserNameAndPassword(employees: any[]) { + const epochTime = Date.now(); + employees.forEach((employee) => { + const { user, "!row#number!": rowNumber } = employee; + const nameInitials = user.name.split(' ').map((name: any) => name.charAt(0)).join(''); + const generatedCode = `${nameInitials}${generateHash(`${epochTime}`)}${rowNumber}`; + const generatedPassword = config?.user?.userPasswordAutoGenerate == "true" ? generateUserPassword() : config?.user?.userDefaultPassword + user.userName = generatedCode; + user.password = generatedPassword; + employee.code = generatedCode + }); +} + async function enrichJurisdictions(employee: any, request: any) { employee.jurisdictions = [ { @@ -1132,199 +615,91 @@ async function enrichJurisdictions(employee: any, request: any) { boundaryType: config.values.userMainBoundaryType, boundary: config.values.userMainBoundary, hierarchy: request?.body?.ResourceDetails?.hierarchyType, - roles: employee?.user?.roles, - }, - ]; + roles: employee?.user?.roles + } + ] } async function enrichEmployees(employees: any[], request: any) { - convertUserRoles(employees, request); - const idRequests = createIdRequests(employees); - request.body.idRequests = idRequests; - let result = await createUniqueUserNameViaIdGen(request); - var i = 0; + convertUserRoles(employees, request) for (const employee of employees) { - const { user } = employee; - const generatedPassword = - config?.user?.userPasswordAutoGenerate == "true" - ? generateUserPassword() - : config?.user?.userDefaultPassword; - user.userName = result?.idResponses?.[i]?.id; - user.password = generatedPassword; - employee.code = result?.idResponses?.[i]?.id; - await enrichJurisdictions(employee, request); + enrichUserNameAndPassword(employees) + await enrichJurisdictions(employee, request) if (employee?.user) { - employee.user.tenantId = request?.body?.ResourceDetails?.tenantId; - employee.user.dob = 0; + employee.user.tenantId = request?.body?.ResourceDetails?.tenantId + employee.user.dob = 0 } - i++; } } -function enrichDataToCreateForUser( - dataToCreate: any[], - responsePayload: any, - request: any -) { +function enrichDataToCreateForUser(dataToCreate: any[], responsePayload: any, request: any) { const createdEmployees = responsePayload?.Employees; - // create an object which have keys as employee.code and values as employee.uuid + // create an object which have keys as employee.code and values as employee.uuid const employeeMap = createdEmployees.reduce((map: any, employee: any) => { - map[employee.code] = { - uuid: employee?.uuid, - userServiceUuid: employee?.user?.userServiceUuid, - }; + map[employee.code] = employee.uuid; return map; }, {}); for (const employee of dataToCreate) { - const mappedEmployee = employeeMap[employee?.code]; - if (mappedEmployee) { - if (!employee?.userServiceUuid) { - employee.userServiceUuid = mappedEmployee.userServiceUuid; - } - if (!employee?.uuid) { - employee.uuid = mappedEmployee.uuid; - } + if (!employee?.uuid && employeeMap[employee?.code]) { + employee.uuid = employeeMap[employee?.code]; } } } -async function handeFacilityProcess( - request: any, - createAndSearchConfig: any, - params: any, - activities: any[], - newRequestBody: any -) { +async function handeFacilityProcess(request: any, createAndSearchConfig: any, params: any, activities: any[], newRequestBody: any) { for (const facility of newRequestBody.Facilities) { - facility.address = {}; + facility.address = {} } - var responsePayload = await httpRequest( - createAndSearchConfig?.createBulkDetails?.url, - newRequestBody, - params, - "post", - undefined, - undefined, - true - ); - var activity = await generateActivityMessage( - request?.body?.ResourceDetails?.tenantId, - request.body, - newRequestBody, - responsePayload, - "facility", - createAndSearchConfig?.createBulkDetails?.url, - responsePayload?.statusCode - ); - logger.info( - `Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}` - ); + var responsePayload = await httpRequest(createAndSearchConfig?.createBulkDetails?.url, newRequestBody, params, "post", undefined, undefined, true); + var activity = await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, responsePayload, "facility", createAndSearchConfig?.createBulkDetails?.url, responsePayload?.statusCode) + logger.info(`Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}`); activities.push(activity); } -async function handleUserProcess( - request: any, - createAndSearchConfig: any, - params: any, - dataToCreate: any[], - activities: any[], - newRequestBody: any -) { + +async function handleUserProcess(request: any, createAndSearchConfig: any, params: any, dataToCreate: any[], activities: any[], newRequestBody: any) { if (config.values.notCreateUserIfAlreadyThere) { - var Employees: any[] = []; + var Employees: any[] = [] if (request.body?.mobileNumberUuidsMapping) { for (const employee of newRequestBody.Employees) { - if ( - request.body.mobileNumberUuidsMapping[employee?.user?.mobileNumber] - ) { - logger.info( - `User with mobile number ${employee?.user?.mobileNumber} already exist` - ); - } else { - Employees.push(employee); + if (request.body.mobileNumberUuidsMapping[employee?.user?.mobileNumber]) { + logger.info(`User with mobile number ${employee?.user?.mobileNumber} already exist`); + } + else { + Employees.push(employee) } } } - newRequestBody.Employees = Employees; + newRequestBody.Employees = Employees } if (newRequestBody.Employees.length > 0) { - var responsePayload = await httpRequest( - createAndSearchConfig?.createBulkDetails?.url, - newRequestBody, - params, - "post", - undefined, - undefined, - true, - false - ); + var responsePayload = await httpRequest(createAndSearchConfig?.createBulkDetails?.url, newRequestBody, params, "post", undefined, undefined, true, true); if (responsePayload?.Employees && responsePayload?.Employees?.length > 0) { enrichDataToCreateForUser(dataToCreate, responsePayload, request); - } else { - throwError( - "COMMON", - 500, - "INTERNAL_SERVER_ERROR", - "Some internal server error occured during user creation." - ); } - var activity = await generateActivityMessage( - request?.body?.ResourceDetails?.tenantId, - request.body, - newRequestBody, - responsePayload, - "user", - createAndSearchConfig?.createBulkDetails?.url, - responsePayload?.statusCode - ); - logger.info( - `Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}` - ); + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Some internal server error occured during user creation."); + } + var activity = await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, responsePayload, "user", createAndSearchConfig?.createBulkDetails?.url, responsePayload?.statusCode) + logger.info(`Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}`); activities.push(activity); } } async function enrichAlreadyExsistingUser(request: any) { - if ( - request.body.ResourceDetails.type == "user" && - request?.body?.mobileNumberUuidsMapping - ) { + if (request.body.ResourceDetails.type == "user" && request?.body?.mobileNumberUuidsMapping) { for (const employee of request.body.dataToCreate) { - if ( - request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber] - ) { - employee.uuid = - request?.body?.mobileNumberUuidsMapping[ - employee?.user?.mobileNumber - ].userUuid; - employee.code = - request?.body?.mobileNumberUuidsMapping[ - employee?.user?.mobileNumber - ].code; - employee.user.userName = - request?.body?.mobileNumberUuidsMapping[ - employee?.user?.mobileNumber - ].code; - employee.user.password = - request?.body?.mobileNumberUuidsMapping[ - employee?.user?.mobileNumber - ].password; - employee.user.userServiceUuid = - request?.body?.mobileNumberUuidsMapping[ - employee?.user?.mobileNumber - ].userServiceUuid; + if (request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber]) { + employee.uuid = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].userUuid; + employee.code = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].code; + employee.user.userName = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].code; + employee.user.password = config.user.userDefaultPassword; } } } } -async function performAndSaveResourceActivity( - request: any, - createAndSearchConfig: any, - params: any, - type: any, - localizationMap?: { [key: string]: string } -) { +async function performAndSaveResourceActivity(request: any, createAndSearchConfig: any, params: any, type: any, localizationMap?: { [key: string]: string }) { logger.info(type + " create data "); if (createAndSearchConfig?.createBulkDetails?.limit) { const limit = createAndSearchConfig?.createBulkDetails?.limit; @@ -1338,46 +713,20 @@ async function performAndSaveResourceActivity( const chunkData = dataToCreate.slice(start, end); // Get a chunk of data const newRequestBody: any = { RequestInfo: request?.body?.RequestInfo, - }; - _.set( - newRequestBody, - createAndSearchConfig?.createBulkDetails?.createPath, - chunkData - ); + } + _.set(newRequestBody, createAndSearchConfig?.createBulkDetails?.createPath, chunkData); creationTime = Date.now(); - if (type == "facility" || type == "facilityMicroplan") { - await handeFacilityProcess( - request, - createAndSearchConfig, - params, - activities, - newRequestBody - ); - } else if (type == "user") { - await handleUserProcess( - request, - createAndSearchConfig, - params, - chunkData, - activities, - newRequestBody - ); + if (type == "facility") { + await handeFacilityProcess(request, createAndSearchConfig, params, activities, newRequestBody); + } + else if (type == "user") { + await handleUserProcess(request, createAndSearchConfig, params, chunkData, activities, newRequestBody); } - // wait for 5 seconds after each chunk - logger.info(`Waiting for 5 seconds after each chunk`); - await new Promise((resolve) => setTimeout(resolve, 5000)); } await enrichAlreadyExsistingUser(request); - logger.info(`Final waiting for 10 seconds`); - await new Promise((resolve) => setTimeout(resolve, 10000)); - await confirmCreation( - createAndSearchConfig, - request, - dataToCreate, - creationTime, - activities - ); - await createPlanFacilityForMicroplan(request, localizationMap); + logger.info(`Waiting for 10 seconds`); + await new Promise(resolve => setTimeout(resolve, 10000)); + await confirmCreation(createAndSearchConfig, request, dataToCreate, creationTime, activities); } await generateProcessedFileAndPersist(request, localizationMap); } @@ -1386,33 +735,13 @@ async function performAndSaveResourceActivity( * Processes generic requests such as create or validate. * @param request The HTTP request object. */ -async function processGenericRequest( - request: any, - localizationMap?: { [key: string]: string } -) { +async function processGenericRequest(request: any, localizationMap?: { [key: string]: string }) { // Process generic requests - if ( - request?.body?.ResourceDetails?.type != "boundary" && - request?.body?.ResourceDetails?.type != "boundaryManagement" - ) { - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - if ( - campaignObject?.additionalDetails?.resourceDistributionStrategy == - "HOUSE_TO_HOUSE" - ) { - request.body.showFixedPost = false; - } else { - request.body.showFixedPost = true; - } - request.body.projectTypeCode = campaignObject?.projectType; - await checkAndGiveIfParentCampaignAvailable(request, campaignObject); - } - if (request?.body?.ResourceDetails?.action == "create") { - await processCreate(request, localizationMap); - } else { - await processValidate(request, localizationMap); + await processCreate(request, localizationMap) + } + else { + await processValidate(request, localizationMap) } } @@ -1420,139 +749,60 @@ async function handleResouceDetailsError(request: any, error: any) { var stringifiedError: any; if (error?.description || error?.message) { stringifiedError = JSON.stringify({ - status: error.status || "", - code: error.code || "", - description: error.description || "", - message: error.message || "", + status: error.status || '', + code: error.code || '', + description: error.description || '', + message: error.message || '' }); - } else { - if (typeof error == "object") stringifiedError = JSON.stringify(error); + } + else { + if (typeof error == "object") + stringifiedError = JSON.stringify(error); else { - stringifiedError = error; + stringifiedError = error } } - logger.error("Error while processing after validation : " + error); + logger.error("Error while processing after validation : " + error) if (request?.body?.ResourceDetails) { request.body.ResourceDetails.status = "failed"; request.body.ResourceDetails.additionalDetails = { ...request?.body?.ResourceDetails?.additionalDetails, - error: stringifiedError, - }; - const persistMessage: any = { - ResourceDetails: request.body.ResourceDetails, + error: stringifiedError }; + const persistMessage: any = { ResourceDetails: request.body.ResourceDetails } if (request?.body?.ResourceDetails?.action == "create") { - persistMessage.ResourceDetails.additionalDetails = { - error: stringifiedError, - }; + persistMessage.ResourceDetails.additionalDetails = { error: stringifiedError } } - await produceModifiedMessages( - persistMessage, - config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC - ); + produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); } - if ( - request?.body?.Activities && - Array.isArray(request?.body?.Activities) && - request?.body?.Activities.length > 0 - ) { + if (request?.body?.Activities && Array.isArray(request?.body?.Activities && request?.body?.Activities.length > 0)) { logger.info("Waiting for 2 seconds"); - await new Promise((resolve) => setTimeout(resolve, 2000)); - - const activities = request?.body?.Activities; - const chunkPromises = []; - for (let i = 0; i < activities.length; i += 10) { - const chunk = activities.slice(i, Math.min(i + 10, activities.length)); - const activityObject: any = { Activities: chunk }; - chunkPromises.push( - produceModifiedMessages( - activityObject, - config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC - ) - ); - } - await Promise.all(chunkPromises); - } -} - -async function persistCreationProcess(request: any, status: any) { - if (request?.body?.ResourceDetails?.type == "facility") { - await persistTrack( - request?.body?.ResourceDetails?.campaignId, - processTrackTypes.facilityCreation, - status - ); - } else if (request?.body?.ResourceDetails?.type == "user") { - await persistTrack( - request?.body?.ResourceDetails?.campaignId, - processTrackTypes.staffCreation, - status - ); + await new Promise(resolve => setTimeout(resolve, 2000)); + produceModifiedMessages(request?.body, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); } } -async function processAfterValidation( - dataFromSheet: any, - createAndSearchConfig: any, - request: any, - localizationMap?: { [key: string]: string } -) { - await persistCreationProcess(request, processTrackStatuses.inprogress); +async function processAfterValidation(dataFromSheet: any, createAndSearchConfig: any, request: any, localizationMap?: { [key: string]: string }) { try { - validateEmptyActive(dataFromSheet, request?.body?.ResourceDetails?.type, localizationMap); - if ( - request?.body?.ResourceDetails?.additionalDetails?.source == - "microplan" && - request.body.ResourceDetails.type == "user" - ) { - await processSearchAndValidation(request); - } else { - const typeData = await convertToTypeData( - request, - dataFromSheet, - createAndSearchConfig, - request.body, - localizationMap - ); - request.body.dataToCreate = typeData.createData; - request.body.dataToSearch = typeData.searchData; - await processSearchAndValidation(request); - await reorderBoundariesOfDataAndValidate(request, localizationMap); - } - if ( - createAndSearchConfig?.createBulkDetails && - request.body.ResourceDetails.status != "invalid" - ) { - _.set( - request.body, - createAndSearchConfig?.createBulkDetails?.createPath, - request?.body?.dataToCreate - ); - const params: any = getParamsViaElements( - createAndSearchConfig?.createBulkDetails?.createElements, - request - ); - changeBodyViaElements( - createAndSearchConfig?.createBulkDetails?.createElements, - request - ); - await performAndSaveResourceActivity( - request, - createAndSearchConfig, - params, - request.body.ResourceDetails.type, - localizationMap - ); - } else if (request.body.ResourceDetails.status == "invalid") { + const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) + request.body.dataToCreate = typeData.createData; + request.body.dataToSearch = typeData.searchData; + await processSearchAndValidation(request, createAndSearchConfig, dataFromSheet) + await reorderBoundariesOfDataAndValidate(request, localizationMap) + if (createAndSearchConfig?.createBulkDetails && request.body.ResourceDetails.status != "invalid") { + _.set(request.body, createAndSearchConfig?.createBulkDetails?.createPath, request?.body?.dataToCreate); + const params: any = getParamsViaElements(createAndSearchConfig?.createBulkDetails?.createElements, request); + changeBodyViaElements(createAndSearchConfig?.createBulkDetails?.createElements, request) + await performAndSaveResourceActivity(request, createAndSearchConfig, params, request.body.ResourceDetails.type, localizationMap); + } + else if (request.body.ResourceDetails.status == "invalid") { await generateProcessedFileAndPersist(request, localizationMap); } } catch (error: any) { - console.log(error); - await persistCreationProcess(request, processTrackStatuses.failed); - await handleResouceDetailsError(request, error); + console.log(error) + await handleResouceDetailsError(request, error) } - await persistCreationProcess(request, processTrackStatuses.completed); } /** @@ -1563,151 +813,28 @@ async function processCreate(request: any, localizationMap?: any) { // Process creation of resources const type: string = request.body.ResourceDetails.type; const tenantId = request?.body?.ResourceDetails?.tenantId; - if (type == "boundary" || type == "boundaryManagement") { + if (type == "boundary") { boundaryBulkUpload(request, localizationMap); - } else if (type == "boundaryGeometryManagement") { - await boundaryGeometryManagement(request, localizationMap); - } else { - // console.log(`Source is MICROPLAN -->`, source); - let createAndSearchConfig: any; - createAndSearchConfig = createAndSearch[type]; - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignType = - responseFromCampaignSearch?.CampaignDetails[0]?.projectType; - if (checkIfSourceIsMicroplan(request?.body?.ResourceDetails)) { - logger.info(`Data create Source is MICROPLAN`); - if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { - createAndSearchConfig.parseArrayConfig.parseLogic = - createAndSearchConfig.parseArrayConfig.parseLogic.map((item: any) => { - if (item.sheetColumn === "E") { - item.sheetColumnName += `_${campaignType}`; - } - return item; - }); - } - } - - const dataFromSheet = await getDataFromSheet( - request, - request?.body?.ResourceDetails?.fileStoreId, - request?.body?.ResourceDetails?.tenantId, - createAndSearchConfig, - undefined, - localizationMap - ); - const schema = await getSchema(request, tenantId, type, campaignType); - await processAfterGettingSchema( - dataFromSheet, - schema, - request, - createAndSearchConfig, - localizationMap - ); } -} - -async function getSchema( - request: any, - tenantId: string, - type: string, - campaignType: string -) { - let schema: any; - const isUpdate = request?.body?.parentCampaignObject ? true : false; - if (type == "facility") { - logger.info( - "Fetching schema to validate the created data for type: " + type - ); - const mdmsResponse = await callMdmsTypeSchema( - request, - tenantId, - isUpdate, - type - ); - schema = mdmsResponse; - } else if (type == "facilityMicroplan") { - const mdmsResponse = await callMdmsTypeSchema( - request, - tenantId, - isUpdate, - "facility", - "microplan" - ); - schema = mdmsResponse; - logger.info( - "Appending project type to capacity for microplan " + campaignType - ); - schema = await appendProjectTypeToCapacity(schema, campaignType); - } else if (type == "user") { - logger.info( - "Fetching schema to validate the created data for type: " + type - ); - if ( - request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" - ) { - const mdmsResponse = await callMdmsTypeSchema( - request, - tenantId, - isUpdate, - type, - "microplan" - ); - schema = mdmsResponse; - } else { - const mdmsResponse = await callMdmsTypeSchema( - request, - tenantId, - isUpdate, - type - ); - schema = mdmsResponse; + else { + const createAndSearchConfig = createAndSearch[type] + const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, undefined, localizationMap) + let schema: any; + if (type == "facility") { + logger.info("Fetching schema to validate the created data for type: " + type); + const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); + schema = mdmsResponse } - } - return schema; -} - -async function processAfterGettingSchema( - dataFromSheet: any, - schema: any, - request: any, - createAndSearchConfig: any, - localizationMap?: any -) { - logger.info("translating schema"); - const translatedSchema = await translateSchema(schema, localizationMap); - if (Array.isArray(dataFromSheet)) { - await validateSheetData( - dataFromSheet, - request, - translatedSchema, - createAndSearchConfig?.boundaryValidation, - localizationMap - ); - logger.info("validation done sucessfully"); - processAfterValidation( - dataFromSheet, - createAndSearchConfig, - request, - localizationMap - ); - } else { - if (dataFromSheet && Object.keys(dataFromSheet).length > 0) { - processSheetWise( - true, - dataFromSheet, - request, - createAndSearchConfig, - translatedSchema, - localizationMap - ); - } else { - throwError( - "COMMON", - 400, - "VALIDATION_ERROR", - "No data filled in the sheet." - ); + else if (type == "user") { + logger.info("Fetching schema to validate the created data for type: " + type); + const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); + schema = mdmsResponse } + logger.info("translating schema") + const translatedSchema = await translateSchema(schema, localizationMap); + await validateSheetData(dataFromSheet, request, translatedSchema, createAndSearchConfig?.boundaryValidation, localizationMap); + logger.info("validation done sucessfully") + processAfterValidation(dataFromSheet, createAndSearchConfig, request, localizationMap) } } @@ -1716,65 +843,33 @@ async function processAfterGettingSchema( * @param request The HTTP request object. */ async function createProjectCampaignResourcData(request: any) { - await persistTrack( - request.body.CampaignDetails.id, - processTrackTypes.triggerResourceCreation, - processTrackStatuses.inprogress - ); - try { - // Create resources for a project campaign - if ( - request?.body?.CampaignDetails?.action == "create" && - request?.body?.CampaignDetails?.resources - ) { - for (const resource of request?.body?.CampaignDetails?.resources) { - const action = - resource?.type === "boundaryWithTarget" ? "validate" : "create"; - // if (resource.type != "boundaryWithTarget") { + // Create resources for a project campaign + if (request?.body?.CampaignDetails?.action == "create" && request?.body?.CampaignDetails?.resources) { + for (const resource of request?.body?.CampaignDetails?.resources) { + if (resource.type != "boundaryWithTarget") { const resourceDetails = { type: resource.type, fileStoreId: resource.filestoreId, tenantId: request?.body?.CampaignDetails?.tenantId, - action: action, + action: "create", hierarchyType: request?.body?.CampaignDetails?.hierarchyType, additionalDetails: {}, - campaignId: request?.body?.CampaignDetails?.id, + campaignId: request?.body?.CampaignDetails?.id }; - logger.info(`Creating the resources for type ${resource.type}`); - logger.debug( - "resourceDetails " + getFormattedStringForDebug(resourceDetails) - ); + logger.info(`Creating the resources for type ${resource.type}`) + logger.debug("resourceDetails " + getFormattedStringForDebug(resourceDetails)) const createRequestBody = { RequestInfo: request.body.RequestInfo, - ResourceDetails: resourceDetails, - }; - const req = replicateRequest(request, createRequestBody); - const res: any = await createDataService(req); + ResourceDetails: resourceDetails + } + const req = replicateRequest(request, createRequestBody) + const res: any = await createDataService(req) if (res?.id) { - resource.createResourceId = res?.id; + resource.createResourceId = res?.id } } } - } catch (error: any) { - console.log(error); - await persistTrack( - request?.body?.CampaignDetails?.id, - processTrackTypes.triggerResourceCreation, - processTrackStatuses.failed, - { - error: String( - error?.message + - (error?.description ? ` : ${error?.description}` : "") || error - ), - } - ); - throw new Error(error); } - await persistTrack( - request.body.CampaignDetails.id, - processTrackTypes.triggerResourceCreation, - processTrackStatuses.completed - ); } async function confirmProjectParentCreation(request: any, projectId: any) { @@ -1783,121 +878,46 @@ async function confirmProjectParentCreation(request: any, projectId: any) { Projects: [ { id: projectId, - tenantId: request.body.CampaignDetails.tenantId, - }, - ], - }; + tenantId: request.body.CampaignDetails.tenantId + } + ] + } const params = { tenantId: request.body.CampaignDetails.tenantId, offset: 0, - limit: 5, - }; + limit: 5 + } var projectFound = false; var retry = 6; while (!projectFound && retry >= 0) { - const response = await httpRequest( - config.host.projectHost + config.paths.projectSearch, - searchBody, - params - ); + const response = await httpRequest(config.host.projectHost + config.paths.projectSearch, searchBody, params); if (response?.Project?.[0]) { projectFound = true; - } else { + } + else { logger.info("Project not found. Waiting for 1 seconds"); - retry = retry - 1; + retry = retry - 1 logger.info(`Waiting for ${retry} for 1 more second`); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await new Promise(resolve => setTimeout(resolve, 1000)); } } if (!projectFound) { - throwError( - "PROJECT", - 500, - "PROJECT_CONFIRMATION_FAILED", - "Project confirmation failed, for the project with id " + projectId - ); + throwError("PROJECT", 500, "PROJECT_CONFIRMATION_FAILED", "Project confirmation failed, for the project with id " + projectId); } } async function projectCreate(projectCreateBody: any, request: any) { - logger.info("Project creation API started"); - logger.debug( - "Project creation body " + getFormattedStringForDebug(projectCreateBody) - ); - if (!request.body.newlyCreatedBoundaryProjectMap) { - request.body.newlyCreatedBoundaryProjectMap = {}; - } - const projectCreateResponse = await httpRequest( - config.host.projectHost + config.paths.projectCreate, - projectCreateBody, - undefined, - undefined, - undefined, - undefined, - undefined, - true - ); - logger.debug( - "Project creation response" + - getFormattedStringForDebug(projectCreateResponse) - ); + logger.info("Project creation API started") + logger.debug("Project creation body " + getFormattedStringForDebug(projectCreateBody)) + const projectCreateResponse = await httpRequest(config.host.projectHost + config.paths.projectCreate, projectCreateBody, undefined, undefined, undefined, undefined, undefined, true); + logger.debug("Project creation response" + getFormattedStringForDebug(projectCreateResponse)) if (projectCreateResponse?.Project[0]?.id) { - logger.info( - "Project created successfully with name " + - JSON.stringify(projectCreateResponse?.Project[0]?.name) - ); - logger.info( - `for boundary type ${projectCreateResponse?.Project[0]?.address?.boundaryType} and code ${projectCreateResponse?.Project[0]?.address?.boundary}` - ); - // if ( - // !request.body.newlyCreatedBoundaryProjectMap[ - // projectCreateBody?.Projects?.[0]?.address?.boundary - // ] - // ) { - // request.body.newlyCreatedBoundaryProjectMap[ - // projectCreateBody?.Projects?.[0]?.address?.boundary - // ] = {}; - // } - request.body.boundaryProjectMapping[ - projectCreateBody?.Projects?.[0]?.address?.boundary - ].projectId = projectCreateResponse?.Project[0]?.id; - // request.body.newlyCreatedBoundaryProjectMap[ - // projectCreateBody?.Projects?.[0]?.address?.boundary - // ].projectId = projectCreateResponse?.Project[0]?.id; - } else { - throwError( - "PROJECT", - 500, - "PROJECT_CREATION_FAILED", - "Project creation failed, for the request: " + - JSON.stringify(projectCreateBody) - ); + logger.info("Project created successfully with name " + JSON.stringify(projectCreateResponse?.Project[0]?.name)) + logger.info(`for boundary type ${projectCreateResponse?.Project[0]?.address?.boundaryType} and code ${projectCreateResponse?.Project[0]?.address?.boundary}`) + request.body.boundaryProjectMapping[projectCreateBody?.Projects?.[0]?.address?.boundary].projectId = projectCreateResponse?.Project[0]?.id } -} - -async function projectUpdateForTargets(projectUpdateBody: any, request: any, boundaryCode: any) { - logger.info("Project Update For Targets started"); - - logger.debug("Project update request body: " + getFormattedStringForDebug(projectUpdateBody)); - logger.info(`Project update started for boundary code: ${boundaryCode} and project name: ${request?.body?.CampaignDetails?.campaignName}`); - - try { - const projectUpdateResponse = await httpRequest( - config.host.projectHost + config.paths.projectUpdate, - projectUpdateBody, - undefined, undefined, undefined, undefined, undefined, - true - ); - logger.debug("Project update response: " + getFormattedStringForDebug(projectUpdateResponse)); - logger.info(`Project update response for boundary code: ${boundaryCode} and project name: ${request?.body?.CampaignDetails?.campaignName}`); - } catch (error: any) { - logger.error("Project update failed", error); - throwError( - "PROJECT", - 500, - "PROJECT_UPDATE_ERROR", - `Project update failed for the request: ${getFormattedStringForDebug(projectUpdateBody)}. Error: ${getFormattedStringForDebug(error.message)}` - ); + else { + throwError("PROJECT", 500, "PROJECT_CREATION_FAILED", "Project creation failed, for the request: " + JSON.stringify(projectCreateBody)); } } @@ -1909,7 +929,7 @@ function generateHierarchyList(data: any[], parentChain: any = []) { let currentChain = [...parentChain, boundary.code]; // Add the current chain to the result - result.push(currentChain.join(",")); + result.push(currentChain.join(',')); // If there are children, recursively call the function if (boundary.children && boundary.children.length > 0) { @@ -1918,69 +938,52 @@ function generateHierarchyList(data: any[], parentChain: any = []) { } } return result; + } -const getHierarchy = async ( - request: any, - tenantId: string, - hierarchyType: string -) => { - const BoundaryTypeHierarchySearchCriteria: BoundaryModels.BoundaryHierarchyDefinitionSearchCriteria = - { - BoundaryTypeHierarchySearchCriteria: { - tenantId, - hierarchyType, - }, +const getHierarchy = async (request: any, tenantId: string, hierarchyType: string) => { + const url = `${config.host.boundaryHost}${config.paths.boundaryHierarchy}`; + + // Create request body + const requestBody = { + "RequestInfo": request?.body?.RequestInfo, + "BoundaryTypeHierarchySearchCriteria": { + "tenantId": tenantId, + "limit": 5, + "offset": 0, + "hierarchyType": hierarchyType + } }; - const response: BoundaryModels.BoundaryHierarchyDefinitionResponse = - await searchBoundaryRelationshipDefinition( - BoundaryTypeHierarchySearchCriteria - ); + + const response = await httpRequest(url, requestBody); const boundaryList = response?.BoundaryHierarchy?.[0].boundaryHierarchy; return generateHierarchy(boundaryList); }; -const getHeadersOfBoundarySheet = async ( - fileUrl: string, - sheetName: string, - getRow = false, - localizationMap?: any -) => { - const localizedBoundarySheetName = getLocalizedName( - sheetName, - localizationMap - ); - const workbook: any = await getExcelWorkbookFromFileURL( - fileUrl, - localizedBoundarySheetName - ); +const getHeadersOfBoundarySheet = async (fileUrl: string, sheetName: string, getRow = false, localizationMap?: any) => { + const localizedBoundarySheetName = getLocalizedName(sheetName, localizationMap); + const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, localizedBoundarySheetName); const worksheet = workbook.getWorksheet(localizedBoundarySheetName); - const columnsToValidate = worksheet - .getRow(1) - .values.map((header: any) => - header ? header.toString().trim() : undefined - ); + const columnsToValidate = worksheet.getRow(1).values.map((header: any) => header ? header.toString().trim() : undefined); // Filter out empty items and return the result - return columnsToValidate.filter((header: any) => typeof header === "string"); -}; + return columnsToValidate.filter((header: any) => typeof header === 'string'); +} + async function getCampaignSearchResponse(request: any) { try { logger.info(`searching for campaign details`); -const CampaignDetails = { - tenantId: request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, - ids: [request?.query?.campaignId || request?.body?.ResourceDetails?.campaignId], -}; - const projectTypeSearchResponse: any = - await searchProjectTypeCampaignService(CampaignDetails); + const requestInfo = { "RequestInfo": request?.body?.RequestInfo }; + const campaignDetails = { "CampaignDetails": { tenantId: request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, "ids": [request?.query?.campaignId || request?.body?.ResourceDetails?.campaignId] } } + const requestBody = { ...requestInfo, ...campaignDetails }; + const req: any = replicateRequest(request, requestBody) + const projectTypeSearchResponse: any = await searchProjectTypeCampaignService(req); return projectTypeSearchResponse; } catch (error: any) { - logger.error( - `Error while searching for campaign details: ${error.message}` - ); - throwError("COMMON", 400, "RESPONSE_NOT_FOUND_ERROR", error?.message); + logger.error(`Error while searching for campaign details: ${error.message}`); + throwError("COMMON", 400, "RESPONSE_NOT_FOUND_ERROR", error?.message) } } @@ -2000,6 +1003,5 @@ export { getHeadersOfBoundarySheet, handleResouceDetailsError, getCampaignSearchResponse, - confirmProjectParentCreation, - projectUpdateForTargets + confirmProjectParentCreation }; diff --git a/health-services/project-factory/src/server/api/coreApis.ts b/health-services/project-factory/src/server/api/coreApis.ts deleted file mode 100644 index aa9ba13003c..00000000000 --- a/health-services/project-factory/src/server/api/coreApis.ts +++ /dev/null @@ -1,259 +0,0 @@ -// Import necessary types and utilities -import { BoundaryModels, MDMSModels } from "../models"; -import config from "../config"; -import { httpRequest } from "../utils/request"; - -// Default request information for MDMS API requests -export const defaultRequestInfo: any = { - RequestInfo: { - apiId: "PROJECTFACTORY", // Identifier for the calling application, - msgId: `${new Date().getTime()}|${config.localisation.defaultLocale}`, - ...(config.isProduction && config.token && { authToken :config.token}), - ...{ userInfo:{ - tenantId:config?.app?.defaultTenantId - }}, - }, -}; - -/** - * Searches MDMS data via the v2 API for specific unique identifiers. - * - * @author jagankumar-egov - * - * @param MdmsCriteria - The criteria for the MDMS v2 search, including tenantId and schemaCode. - * @returns Promise resolving to the MDMS v2 search response containing matched data. - */ -const searchMDMSDataViaV2Api = async ( - MdmsCriteria: MDMSModels.MDMSv2RequestCriteria -): Promise => { - // Construct the full API URL for the v2 MDMS search - const apiUrl: string = config.host.mdmsV2 + config.paths.mdms_v2_search; - - // Prepare the data payload for the API request - const data = { - MdmsCriteria, - ...defaultRequestInfo, - }; - - // Make an HTTP request to the MDMS v2 API - const response: MDMSModels.MDMSv2Response = await httpRequest(apiUrl, data); - - // Return the response from the API - return response; -}; - -/** - * Fetches the schema definitions from MDMS based on specified criteria. - * - * @author jagankumar-egov - * - * @param SchemaDefCriteria - The criteria for fetching schema definitions, including tenantId and limit. - * @returns Promise resolving to the response containing schema definitions. - */ -const searchMDMSSchema = async ( - SchemaDefCriteria: MDMSModels.MDMSSchemaRequestCriteria -): Promise => { - // Construct the request body including schema criteria and default request info - const requestBody = { - ...SchemaDefCriteria, - ...defaultRequestInfo, - }; - - // Define the API URL for schema retrieval - const url = config.host.mdmsV2 + config.paths.mdmsSchema; - - // Make an HTTP request with a tenant ID in headers - const response: MDMSModels.MDMSSchemaResponse = await httpRequest( - url, - requestBody, - { tenantId: SchemaDefCriteria?.SchemaDefCriteria?.tenantId } - ); - - // Return the schema definitions from the response - return response; -}; - -/** - * Searches MDMS data via the v1 API using given criteria. - * - * @author jagankumar-egov - * - * @param MdmsCriteria - The criteria for the MDMS v1 search, including tenantId and moduleDetails. - * @returns Promise resolving to the MDMS v1 search response. - */ -const searchMDMSDataViaV1Api = async ( - MdmsCriteria: MDMSModels.MDMSv1RequestCriteria -): Promise => { - // Construct the request body with v1 search criteria and default request info - const requestBody = { - ...MdmsCriteria, - ...defaultRequestInfo, - }; - - // Define the API URL for MDMS v1 search - const url = config.host.mdmsV2 + config.paths.mdms_v1_search; - - // Make an HTTP request with tenant ID in headers - const response: MDMSModels.MDMSv1Response = await httpRequest( - url, - requestBody, - { tenantId: MdmsCriteria.MdmsCriteria.tenantId } - ); - - // Return the search result from MDMS v1 - return response; -}; - - -/** - * Searches boundary entities in the MDMS system using specified criteria. - * - * @author jagankumar-egov - * - * @function searchBoundaryEntity - * @param tenantId - Unique identifier for the tenant. - * @param codes - Specific codes to filter the boundary entities. - * @param limit - Maximum number of results to return (default is 100). - * @param offset - Starting position for fetching results (default is 0). - * @returns Promise resolving to the boundary entity search response. - * - * @remarks - * This function constructs and sends a request to the boundary entity service, - * using the provided criteria to filter and retrieve specific boundary entities. - * Additional headers contain tenant ID, offset, limit, and codes for filtering. - * - * @example - * const response = await searchBoundaryEntity("mz", "MOZ", 50, 0); - */ -const searchBoundaryEntity = async ( - tenantId: string, - codes: string, - limit: number = 100, - offset: number = 0, -): Promise => { - // Prepare request body with default request information - const requestBody = { - ...defaultRequestInfo, - }; - - // Construct API URL for boundary entity search - const url = config.host.boundaryHost + config.paths.boundaryServiceSearch; - - // Execute HTTP request with tenant ID, offset, limit, and codes in headers - const response: BoundaryModels.BoundaryEntityResponse = await httpRequest( - url, - requestBody, - { tenantId, offset, limit, codes } - ); - - // Return the response containing boundary entity data - return response; -}; - -/** - * Searches boundary hierarchy relationship data within the MDMS system. - * - * @author jagankumar-egov - * - * @function searchBoundaryRelationshipData - * @param tenantId - Unique identifier for the tenant. - * @param hierarchyType - Type of hierarchy to search within. - * @param includeChildren - Whether to include child relationships (default is true). - * @param includeParents - Whether to include parent relationships (default is true). - * @returns Promise resolving to the boundary hierarchy relationship response. - * - * @remarks - * This function queries the boundary relationship API to retrieve hierarchy data - * based on the specified hierarchy type and inclusion of child or parent entities. - * - * @example - * const response = await searchBoundaryRelationshipData("mz", "ADMIN", true, false); - */ -const searchBoundaryRelationshipData = async ( - tenantId: string, - hierarchyType: string, - includeChildren: boolean = true, - includeParents: boolean = true, -): Promise => { - // Prepare request body with default request information - const requestBody = { - ...defaultRequestInfo, - }; - - // Construct API URL for boundary hierarchy relationship search - const url = config.host.boundaryHost + config.paths.boundaryRelationship; - - // Execute HTTP request with tenant ID, hierarchy type, and inclusion flags in headers - const response: BoundaryModels.BoundaryHierarchyRelationshipResponse = await httpRequest( - url, - requestBody, - { tenantId, hierarchyType, includeChildren, includeParents } - ); - - // Return the response containing boundary relationship data - return response; -}; - -/** - * Searches boundary hierarchy definitions based on provided search criteria. - * - * @author jagankumar-egov - * - * @function searchBoundaryRelationshipDefinition - * @param BoundaryTypeHierarchySearchCriteria - Criteria for fetching boundary hierarchy definitions. - * @returns Promise resolving to the boundary hierarchy definition response. - * - * @remarks - * This function sends a request to retrieve hierarchy definitions for boundary types, - * based on specified criteria such as tenant ID and hierarchy parameters. - * - * @example - * const criteria = { tenantId: "mz", hierarchyCode: "ADMIN" }; - * const response = await searchBoundaryRelationshipDefinition(criteria); - */ -const searchBoundaryRelationshipDefinition = async ( - BoundaryTypeHierarchySearchCriteria: BoundaryModels.BoundaryHierarchyDefinitionSearchCriteria -): Promise => { - // Prepare request body with search criteria and default request information - const requestBody = { - ...BoundaryTypeHierarchySearchCriteria, - ...defaultRequestInfo, - }; - - // Construct API URL for boundary hierarchy definition search - const url = config.host.boundaryHost + config.paths.boundaryHierarchy; - - // Execute HTTP request to fetch boundary hierarchy definitions - const response: BoundaryModels.BoundaryHierarchyDefinitionResponse = await httpRequest( - url, - requestBody, - ); - - // Return the response containing hierarchy definition data - return response; -}; - - - -const fetchFileFromFilestore=async(filestoreId:string,tenantId:string)=> { - - try { - const reqParamsForFetchingFile = { - tenantId: tenantId, - fileStoreIds: filestoreId - }; - const fileResponse= await httpRequest( - `${config?.host?.filestore}${config?.paths?.filestorefetch}`, - {}, - reqParamsForFetchingFile, - "get" - ); - return fileResponse?.fileStoreIds?.[0].url; - } catch (error) { - console.error("Error fetching file URLs:", error); - throw error; - } -} - -// Exporting all API functions for MDMS operations -export { searchMDMSDataViaV2Api, searchMDMSSchema, searchMDMSDataViaV1Api ,searchBoundaryEntity, searchBoundaryRelationshipData, searchBoundaryRelationshipDefinition ,fetchFileFromFilestore}; diff --git a/health-services/project-factory/src/server/api/genericApis.ts b/health-services/project-factory/src/server/api/genericApis.ts index 2ae5f0f7491..3325efc9d73 100644 --- a/health-services/project-factory/src/server/api/genericApis.ts +++ b/health-services/project-factory/src/server/api/genericApis.ts @@ -6,9 +6,10 @@ import { getFormattedStringForDebug, logger } from "../utils/logger"; // Import import { correctParentValues, findMapValue, generateActivityMessage, getBoundaryRelationshipData, getDataSheetReady, getLocalizedHeaders, sortCampaignDetails, throwError } from "../utils/genericUtils"; // Import utility functions import { extractCodesFromBoundaryRelationshipResponse, generateFilteredBoundaryData, getConfigurableColumnHeadersBasedOnCampaignType, getFiltersFromCampaignSearchResponse, getLocalizedName } from '../utils/campaignUtils'; // Import utility functions import { getCampaignSearchResponse, getHierarchy } from './campaignApis'; +import { validateMappingId } from '../utils/campaignMappingUtils'; +import { campaignStatuses } from '../config/constants'; const _ = require('lodash'); // Import lodash library import { getExcelWorkbookFromFileURL } from "../utils/excelUtils"; -import { processMapping } from "../utils/campaignMappingUtils"; //Function to get Workbook with different tabs (for type target) @@ -37,9 +38,9 @@ const getTargetWorkbook = async (fileUrl: string, localizationMap?: any) => { function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheetName = "sheet1") { const jsonData: any[] = []; - const headers = sheetData[0]; // Extract the headers from the first row + const headers = sheetData[1]; // Extract the headers from the first row - for (let i = 1; i < sheetData.length; i++) { + for (let i = 2; i < sheetData.length; i++) { const rowData: any = {}; const row = sheetData[i]; if (row) { @@ -51,7 +52,7 @@ function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheet } } if (Object.keys(rowData).length > 0) { - if (getRow) rowData["!row#number!"] = i + 1; + if (getRow) rowData["!row#number!"] = i; if (getSheetName) rowData["!sheet#name!"] = sheetName; jsonData.push(rowData); } @@ -60,49 +61,34 @@ function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheet return jsonData; } -// function validateFirstRowColumn(createAndSearchConfig: any, worksheet: any, localizationMap: any) { -// if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { -// const parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic; -// // Iterate over each column configuration -// for (const columnConfig of parseLogic) { -// const { sheetColumn, sheetColumnName } = columnConfig; -// const localizedColumnName = getLocalizedName(sheetColumnName, localizationMap); - -// // Get the value of the first row in the current column -// if (sheetColumn && localizedColumnName) { -// const firstRowValue = worksheet.getCell(sheetColumn + '1').value; - -// // Validate the first row of the current column -// if (firstRowValue !== localizedColumnName) { -// throwError( -// "FILE", -// 400, -// "INVALID_COLUMNS", -// `Invalid format: Expected '${localizedColumnName}' in the first row of column ${sheetColumn}.` -// ); -// } -// } -// } -// } -// } - -function getSheetDataFromWorksheet(worksheet: any) { - var sheetData: any[][] = []; - - worksheet?.eachRow({ includeEmpty: true }, (row: any, rowNumber: any) => { - const rowData: any[] = []; - - row.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { - const cellValue = getRawCellValue(cell); - rowData[colNumber - 1] = cellValue; // Store cell value (0-based index) - }); - - // Push non-empty row only - if (rowData.some(value => value !== null && value !== undefined)) { - sheetData[rowNumber - 1] = rowData; // Store row data (0-based index) +function validateFirstRowColumn(createAndSearchConfig: any, worksheet: any, localizationMap: any) { + if ( + createAndSearchConfig && + createAndSearchConfig.parseArrayConfig && + createAndSearchConfig.parseArrayConfig.parseLogic + ) { + const parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic; + // Iterate over each column configuration + for (const columnConfig of parseLogic) { + const { sheetColumn, sheetColumnName } = columnConfig; + const localizedColumnName = getLocalizedName(sheetColumnName, localizationMap); + + // Get the value of the first row in the current column + if (sheetColumn && localizedColumnName) { + const firstRowValue = worksheet.getCell(sheetColumn + '1').value; + + // Validate the first row of the current column + if (firstRowValue !== localizedColumnName) { + throwError( + "FILE", + 400, + "INVALID_COLUMNS", + `Invalid format: Expected '${localizedColumnName}' in the first row of column ${sheetColumn}.` + ); + } + } } - }); - return sheetData; + } } // Function to retrieve data from a specific sheet in an Excel file @@ -113,57 +99,19 @@ const getSheetData = async ( createAndSearchConfig?: any, localizationMap?: { [key: string]: string } ) => { - // Retrieve workbook using the getExcelWorkbookFromFileURL function + // Retrieve workbook using the getTargetWorkbook function const localizedSheetName = getLocalizedName(sheetName, localizationMap); const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, localizedSheetName); const worksheet: any = workbook.getWorksheet(localizedSheetName); + // If parsing array configuration is provided, validate first row of each column - // validateFirstRowColumn(createAndSearchConfig, worksheet, localizationMap); + validateFirstRowColumn(createAndSearchConfig, worksheet, localizationMap); - // Collect sheet data by iterating through rows and cells - const sheetData = getSheetDataFromWorksheet(worksheet); + const sheetData = worksheet.getSheetValues({ includeEmpty: true }); const jsonData = getJsonData(sheetData, getRow); return jsonData; -}; - -// Helper function to extract raw cell value -function getRawCellValue(cell: any) { - if (cell.value && typeof cell.value === 'object') { - if ('richText' in cell.value) { - // Handle rich text - return cell.value.richText.map((rt: any) => rt.text).join(''); - } - else if ('hyperlink' in cell.value) { - if (cell?.value?.text?.richText?.length > 0) { - return cell.value.text.richText.map((t: any) => t.text).join(''); - } - else { - return cell.value.text; - } - } - else if ('formula' in cell.value) { - // Get the result of the formula - return cell.value.result; - } - else if ('sharedFormula' in cell.value) { - // Get the result of the shared formula - return cell.value.result; - } - else if ('error' in cell.value) { - // Get the error value - return cell.value.error; - } else if (cell.value instanceof Date) { - // Handle date values - return cell.value.toISOString(); - } - else { - // Return as-is for other object types - return cell.value; - } - } - return cell.value; // Return raw value for plain strings, numbers, etc. } const getTargetSheetData = async ( @@ -183,14 +131,13 @@ const getTargetSheetData = async ( for (const sheetName of localizedSheetNames) { const worksheet = workbook.getWorksheet(sheetName); - const sheetData = getSheetDataFromWorksheet(worksheet); + const sheetData = worksheet.getSheetValues({ includeEmpty: true }); workbookData[sheetName] = getJsonData(sheetData, getRow, getSheetName, sheetName); } return workbookData; }; const getTargetSheetDataAfterCode = async ( - request: any, fileUrl: string, getRow = false, getSheetName = false, @@ -208,58 +155,40 @@ const getTargetSheetDataAfterCode = async ( for (const sheetName of localizedSheetNames) { const worksheet = workbook.getWorksheet(sheetName); - const sheetData = getSheetDataFromWorksheet(worksheet); + const sheetData = worksheet.getSheetValues({ includeEmpty: true }); // Find the target column index where the first row value matches codeColumnName - const firstRow = sheetData[0]; - let boundaryCodeColumnIndex = -1; + const firstRow = sheetData[1]; + let targetColumnIndex = -1; for (let colIndex = 1; colIndex < firstRow.length; colIndex++) { if (firstRow[colIndex] === codeColumnName) { - boundaryCodeColumnIndex = colIndex; + targetColumnIndex = colIndex; break; } } - if (boundaryCodeColumnIndex === -1) { + if (targetColumnIndex === -1) { console.warn(`Column "${codeColumnName}" not found in sheet "${sheetName}".`); continue; } // Process data from sheet const processedData = sheetData.map((row: any, rowIndex: any) => { - if (rowIndex <= 0) return null; // Skip header row + if (rowIndex <= 1) return null; // Skip header row - let rowData: any = { [codeColumnName]: row[boundaryCodeColumnIndex] }; + let rowData: any = { [codeColumnName]: row[targetColumnIndex] }; // Add integer values in the target column for the current row - let sumOfCurrentTargets = 0; - let sumOfParentTargets = 0; - const remainingColumns = row.length - boundaryCodeColumnIndex - 1; - const halfPoint = Math.floor(remainingColumns / 2); - let startColIndex = boundaryCodeColumnIndex + 1; - - if (request?.body?.parentCampaign) { - for (let colIndex = startColIndex; colIndex < startColIndex + halfPoint; colIndex++) { - const value = row[colIndex]; - if (typeof value === 'number' && Number.isInteger(value)) { - sumOfParentTargets += value; - } - } - // Add the sum to the row data - rowData['Parent Target at the Selected Boundary level'] = sumOfParentTargets; - - // Calculate middle point of remaining columns - startColIndex = boundaryCodeColumnIndex + 1 + halfPoint; - } - for (let colIndex = startColIndex; colIndex < row.length; colIndex++) { + let sum = 0; + for (let colIndex = targetColumnIndex + 1; colIndex < row.length; colIndex++) { const value = row[colIndex]; if (typeof value === 'number' && Number.isInteger(value)) { - sumOfCurrentTargets += value; + sum += value; } } // Add the sum to the row data - rowData['Target at the Selected Boundary level'] = sumOfCurrentTargets; + rowData['Target at the Selected Boundary level'] = sum; return rowData; }).filter(Boolean); // Remove null entries @@ -282,7 +211,7 @@ const searchMDMS: any = async ( } // Construct API URL for MDMS search - const apiUrl = config.host.mdmsV2 + config.paths.mdms_v2_search; + const apiUrl = config.host.mdms + config.paths.mdms_search; // Construct request data for MDMS search const data = { @@ -409,7 +338,7 @@ const getSchema: any = async (code: string, RequestInfo: any) => { codes: [code], }, }; - const mdmsSearchUrl = config.host.mdmsV2 + config.paths.mdmsSchema; + const mdmsSearchUrl = config.host.mdms + config.paths.mdmsSchema; try { const result = await httpRequest( @@ -468,62 +397,12 @@ async function createAndUploadFile( request: any, tenantId?: any ) { - let retries: any = 3; - while (retries--) { - try { - // Write the updated workbook to a buffer - const buffer = await updatedWorkbook.xlsx.writeBuffer(); - - // Create form data for file upload - const formData = new FormData(); - formData.append("file", buffer, "filename.xlsx"); - formData.append( - "tenantId", - tenantId ? tenantId : request?.body?.RequestInfo?.userInfo?.tenantId - ); - formData.append("module", "HCM-ADMIN-CONSOLE-SERVER"); - - // Make HTTP request to upload file - var fileCreationResult = await httpRequest( - config.host.filestore + config.paths.filestore, - formData, - undefined, - undefined, - undefined, - { - "Content-Type": "multipart/form-data", - "auth-token": request?.body?.RequestInfo?.authToken || request?.RequestInfo?.authToken, - } - ); - - // Extract response data - const responseData = fileCreationResult?.files; - if (responseData) { - return responseData; - } - } - catch (error: any) { - console.error(`Attempt failed:`, error.message); - - // Add a delay before the next retry (2 seconds) - await new Promise((resolve) => setTimeout(resolve, 5000)); - } - } - throw new Error("Error while uploading excel file: INTERNAL_SERVER_ERROR"); -} - -async function createAndUploadJsonFile( - jsonData: any, // Expecting JSON data as an argument - request: any, - tenantId?: any -) { - // Convert JSON data to a string - const jsonString = JSON.stringify(jsonData); - const buffer = Buffer.from(jsonString); + // Write the updated workbook to a buffer + const buffer = await updatedWorkbook.xlsx.writeBuffer(); // Create form data for file upload const formData = new FormData(); - formData.append("file", buffer, { filename: "filename.json", contentType: "application/json" }); + formData.append("file", buffer, "filename.xlsx"); formData.append( "tenantId", tenantId ? tenantId : request?.body?.RequestInfo?.userInfo?.tenantId @@ -547,14 +426,13 @@ async function createAndUploadJsonFile( const responseData = fileCreationResult?.files; if (!responseData) { throw new Error( - "Error while uploading JSON file: INTERNAL_SERVER_ERROR" + "Error while uploading excel file: INTERNAL_SERVER_ERROR" ); } return responseData; // Return the response data } - // Function to generate a list of hierarchy codes function generateHierarchyList(data: any[], parentChain: any = []) { let result: any[] = []; @@ -666,95 +544,51 @@ async function getAutoGeneratedBoundaryCodes(boundaryList: any, childParentMap: for (let i = 0; i < columnsData.length; i++) { const column = columnsData[i]; for (const element of column) { - if (!findMapValue(elementCodesMap, element) && element.value !== '') { - const parentElement = findMapValue(childParentMap, element); - if (parentElement !== undefined && parentElement !== null) { - const parentBoundaryCode = findMapValue(elementCodesMap, parentElement); - const currentCount = (findMapValue(countMap, parentElement) || 0) + 1; - countMap.set(parentElement, currentCount); - - const code = generateElementCode( - currentCount, - parentElement, - parentBoundaryCode, - element.value, - config.excludeBoundaryNameAtLastFromBoundaryCodes, - childParentMap, - elementCodesMap - ); - + if (!findMapValue(elementCodesMap, element)) { + const parentCode = findMapValue(childParentMap, element) + if (parentCode !== undefined && parentCode !== null) { + countMap.set(parentCode, (findMapValue(countMap, parentCode) || 0) + 1); + let code; + const grandParentCode = findMapValue(childParentMap, parentCode); + if (grandParentCode != null && grandParentCode != undefined) { + const parentBoundaryCode = findMapValue(elementCodesMap, parentCode) + const lastUnderscoreIndex = parentBoundaryCode.lastIndexOf('_'); + const parentBoundaryCodeTrimmed = lastUnderscoreIndex !== -1 ? parentBoundaryCode.substring(0, lastUnderscoreIndex) : parentBoundaryCode; + code = generateElementCode(countMap.get(parentCode), parentBoundaryCodeTrimmed, element.value); + } else { + code = generateElementCode(countMap.get(parentCode), findMapValue(elementCodesMap, parentCode), element.value); + } elementCodesMap.set(element, code); // Store the code of the element in the map } else { // Generate default code if parent code is not found - const prefix = config?.excludeHierarchyTypeFromBoundaryCodes - ? element.value.toString().substring(0, 2).toUpperCase() - : `${(request?.body?.ResourceDetails?.hierarchyType + "_").toUpperCase()}${element.value.toString().substring(0, 2).toUpperCase()}`; - - elementCodesMap.set(element, prefix); + elementCodesMap.set(element, (request?.body?.ResourceDetails?.hierarchyType + "_").toUpperCase() + element.value.toString().substring(0, 2).toUpperCase()); } + } else { + continue; } } } - modifyElementCodesMap(elementCodesMap); // Modify the element codes map return elementCodesMap; // Return the updated element codes map } -function modifyElementCodesMap(elementCodesMap: any) { - const set = new Set(); - const specialCharsRegex = /[^\w]/g; // Regular expression to match any character that is not a word character - - // Iterate over each [key, value] pair in elementCodesMap using forEach - elementCodesMap.forEach((value: any, key: any) => { - let modifiedValue = value.replace(specialCharsRegex, '_').trim(); // Replace special characters and spaces with underscore - let modifiedTempValue = modifiedValue; // Store the initial modified value - let count = 1; - - // Generate a unique modified value - while (set.has(modifiedValue)) { - // If it exists, append _ to modifiedValue - modifiedValue = `${modifiedTempValue}_${count}`; - count++; - } - - // Add the modified (or original) value to the set - set.add(modifiedValue); - - // Update the map with the modified value - elementCodesMap.set(key, modifiedValue); - }); - -} - /** * Function to generate an element code based on sequence, parent code, and element. * @param sequence Sequence number - * @param parentElement Parent element - * @param parentBoundaryCode Parent boundary code + * @param parentCode Parent code * @param element Element - * @param excludeBoundaryNameAtLastFromBoundaryCodes Whether to exclude boundary name at last - * @param childParentMap Map of child to parent elements - * @param elementCodesMap Map of elements to their codes * @returns Generated element code */ -function generateElementCode(sequence: any, parentElement: any, parentBoundaryCode: any, element: any, excludeBoundaryNameAtLastFromBoundaryCodes?: any, childParentMap?: any, elementCodesMap?: any) { +function generateElementCode(sequence: any, parentCode: any, element: any) { // Pad single-digit numbers with leading zero - const paddedSequence = sequence.toString().padStart(2, "0"); - let code; - - if (excludeBoundaryNameAtLastFromBoundaryCodes) { - code = `${parentBoundaryCode.toUpperCase()}_${paddedSequence}`; - } else { - const grandParentElement = findMapValue(childParentMap, parentElement); - if (grandParentElement != null && grandParentElement != undefined) { - const lastUnderscoreIndex = parentBoundaryCode ? parentBoundaryCode.lastIndexOf('_') : -1; - const parentBoundaryCodeTrimmed = lastUnderscoreIndex !== -1 ? parentBoundaryCode.substring(0, lastUnderscoreIndex) : parentBoundaryCode; - code = `${parentBoundaryCodeTrimmed.toUpperCase()}_${paddedSequence}_${element.toString().toUpperCase()}`; - } else { - code = `${parentBoundaryCode.toUpperCase()}_${paddedSequence}_${element.toString().toUpperCase()}`; - } - } - - return code.trim(); + let paddedSequence = sequence.toString().padStart(2, "0"); + const code = parentCode.toUpperCase() + + "_" + + paddedSequence + + "_" + + element.toUpperCase(); + return ( + code.trim() + ); } /** @@ -790,14 +624,7 @@ async function getBoundarySheetData( modifiedHierarchy, localizationMap ); - var headerColumnsAfterHierarchy; - if (request?.query?.type != "boundaryManagement" && request?.query?.type !== 'boundaryGeometryManagement') { - headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); - } - - if (request?.query?.type === "boundaryManagement" || request?.query?.type === 'boundaryGeometryManagement') { - headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement(request, localizationMap); - } + const headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); const headers = [...localizedHeadersUptoHierarchy, ...headerColumnsAfterHierarchy]; // create empty sheet if no boundary present in system // const localizedBoundaryTab = getLocalizedName( @@ -810,100 +637,26 @@ async function getBoundarySheetData( headers ); } else { - let Filters: any = {}; - if (request?.body?.Filters && request?.body?.Filters.boundaries && Array.isArray(request?.body?.Filters.boundaries) && request?.body?.Filters.boundaries.length > 0) { - Filters = { - Filters: { - boundaries: request.body.Filters.boundaries.map((boundary: any) => ({ - ...boundary, - boundaryType: boundary.type // Adding boundaryType field - })) - } - }; - } - else if (request?.query?.type !== "boundaryManagement") { - // logger.info("boundaryData for sheet " + JSON.stringify(boundaryData)) - const responseFromCampaignSearch = - await getCampaignSearchResponse(request); - Filters = await getFiltersFromCampaignSearchResponse(request, responseFromCampaignSearch) - } - if (Filters?.Filters && Filters.Filters.boundaries && Array.isArray(Filters.Filters.boundaries) && Filters.Filters.boundaries.length > 0) { + // logger.info("boundaryData for sheet " + JSON.stringify(boundaryData)) + const responseFromCampaignSearch = + await getCampaignSearchResponse(request); + const FiltersFromCampaignId = getFiltersFromCampaignSearchResponse(responseFromCampaignSearch) + if (FiltersFromCampaignId?.Filters != null) { const filteredBoundaryData = await generateFilteredBoundaryData( request, - Filters + FiltersFromCampaignId ); return await getDataSheetReady( filteredBoundaryData, request, localizationMap ); - } - else { + } else { return await getDataSheetReady(boundaryData, request, localizationMap); } } } -async function getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement(request: any, localizationMap?: { [key: string]: string }) { - try { - const mdmsResponse = await callMdmsTypeSchema( - request, - request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, - false, - request?.query?.type || request?.body?.ResourceDetails?.type, - "all" - ); - if (!mdmsResponse || mdmsResponse?.columns.length === 0) { - logger.error( - `Campaign Type all has not any columns configured in schema` - ); - throwError( - "COMMON", - 400, - "SCHEMA_ERROR", - `Campaign Type all has not any columns configured in schema` - ); - } - // Extract columns from the response - const columnsForGivenCampaignId = mdmsResponse?.columns; - - // Get localized headers based on the column names - const headerColumnsAfterHierarchy = getLocalizedHeaders( - columnsForGivenCampaignId, - localizationMap - ); - if ( - !headerColumnsAfterHierarchy.includes( - getLocalizedName(config.boundary.boundaryCode, localizationMap) - ) - ) { - logger.error( - `Column Headers of generated Boundary Template does not have ${getLocalizedName( - config.boundary.boundaryCode, - localizationMap - )} column` - ); - throwError( - "COMMON", - 400, - "VALIDATION_ERROR", - `Column Headers of generated Boundary Template does not have ${getLocalizedName( - config.boundary.boundaryCode, - localizationMap - )} column` - ); - } - return headerColumnsAfterHierarchy; - } catch (error: any) { - console.log(error); - throwError( - "FILE", - 400, - "FETCHING_COLUMN_ERROR", - "Error fetching column Headers From Schema (either boundary code column not found or given Campaign Type not found in schema) Check logs" - ); - } -} async function createStaff(resouceBody: any) { // Create staff const staffCreateUrl = @@ -918,7 +671,8 @@ async function createStaff(resouceBody: any) { undefined, undefined, undefined, - false + false, + true ); logger.info("Project Staff mapping created"); logger.debug( @@ -946,7 +700,8 @@ async function createProjectResource(resouceBody: any) { undefined, undefined, undefined, - false + false, + true ); logger.debug("Project Resource Created"); logger.debug( @@ -974,7 +729,8 @@ async function createProjectFacility(resouceBody: any) { undefined, undefined, undefined, - false + false, + true ); logger.info("Project Facility Created"); logger.debug( @@ -985,63 +741,44 @@ async function createProjectFacility(resouceBody: any) { } // Helper function to create staff -const createProjectStaffHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { - try { - const ProjectStaff = { - tenantId: tenantId.split(".")?.[0], - projectId, - userId: resourceId, - startDate, - endDate, - }; - const newResourceBody = { ...resouceBody, ProjectStaff }; - return createStaff(newResourceBody); - } catch (error) { - // Log the error if the API call fails - logger.error(`Failed to create project staff for staffId ${resourceId}:`, error); - throw error; // Rethrow the error to propagate it - } +const createStaffHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { + const ProjectStaff = { + tenantId: tenantId.split(".")?.[0], + projectId, + userId: resourceId, + startDate, + endDate, + }; + const newResourceBody = { ...resouceBody, ProjectStaff }; + return createStaff(newResourceBody); }; // Helper function to create project resource const createProjectResourceHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { - try { - const ProjectResource = { - tenantId: tenantId.split(".")?.[0], - projectId, - resource: { - productVariantId: resourceId, - type: "DRUG", - isBaseUnitVariant: false, - }, - startDate, - endDate, - }; - const newResourceBody = { ...resouceBody, ProjectResource }; - return createProjectResource(newResourceBody); - } - catch (error) { - // Log the error if the API call fails - logger.error(`Failed to create project resource for resourceId ${resourceId}:`, error); - throw error; // Rethrow the error to propagate it - } + const ProjectResource = { + tenantId: tenantId.split(".")?.[0], + projectId, + resource: { + productVariantId: resourceId, + type: "DRUG", + isBaseUnitVariant: false, + }, + startDate, + endDate, + }; + const newResourceBody = { ...resouceBody, ProjectResource }; + return createProjectResource(newResourceBody); }; // Helper function to create project facility -const createProjectFacilityHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { - try { - const ProjectFacility = { - tenantId: tenantId.split(".")?.[0], - projectId, - facilityId: resourceId, - }; - const newResourceBody = { ...resouceBody, ProjectFacility }; - return createProjectFacility(newResourceBody); - } catch (error) { - // Log the error if the API call fails - logger.error(`Failed to create facility for facilityId ${resourceId}:`, error); - throw error; // Rethrow the error to propagate it - } +const createProjectFacilityHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any) => { + const ProjectFacility = { + tenantId: tenantId.split(".")?.[0], + projectId, + facilityId: resourceId, + }; + const newResourceBody = { ...resouceBody, ProjectFacility }; + return createProjectFacility(newResourceBody); }; @@ -1055,31 +792,32 @@ const createProjectFacilityHelper = (resourceId: any, projectId: any, resouceBod * @param resouceBody The resource body. */ async function createRelatedEntity( - createRelatedEntityArray: any[], - CampaignDetails: any, - requestBody: any + resources: any, + tenantId: any, + projectId: any, + startDate: any, + endDate: any, + resouceBody: any ) { - const mappingArray = [] - for (const entity of createRelatedEntityArray) { - const { tenantId, projectId, startDate, endDate, resouceBody, campaignId, resources } = entity - for (const resource of resources) { - const type = resource?.type; - const mappingObject: any = { - type, - tenantId, - resource, - projectId, - startDate, - endDate, - resouceBody, - campaignId, - CampaignDetails + // Array to hold all promises + const promises = []; + + // Create related entities + for (const resource of resources) { + const type = resource?.type; + for (const resourceId of resource?.resourceIds) { + logger.info(`creating project ${type} mapping for project : ${projectId} and resourceId ${resourceId}`); + if (type === "staff") { + promises.push(createStaffHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)); + } else if (type === "resource") { + promises.push(createProjectResourceHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)); + } else if (type === "facility") { + promises.push(createProjectFacilityHelper(resourceId, projectId, resouceBody, tenantId)); } - mappingArray.push(mappingObject) } } - const mappingObject: any = { mappingArray: mappingArray, CampaignDetails: CampaignDetails, RequestInfo: requestBody?.RequestInfo, parentCampaign: requestBody?.parentCampaign } - await processMapping(mappingObject) + // Wait for all promises to complete + await Promise.all(promises); } @@ -1089,34 +827,32 @@ async function createRelatedEntity( */ async function createRelatedResouce(requestBody: any) { const id = requestBody?.Campaign?.id; - sortCampaignDetails(requestBody?.Campaign?.CampaignDetails); - correctParentValues(requestBody?.Campaign?.CampaignDetails); - // Create related resources - const { tenantId } = requestBody?.Campaign; - const createRelatedEntityArray = []; - for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { - const resouceBody: any = { - RequestInfo: requestBody.RequestInfo, - }; - var { projectId, startDate, endDate, resources } = campaignDetails; - campaignDetails.id = id; - startDate = parseInt(startDate); - endDate = parseInt(endDate); - createRelatedEntityArray.push({ - resources, - tenantId, - projectId, - startDate, - endDate, - resouceBody, - campaignId: id, - }); + const campaignDetails = await validateMappingId(requestBody, id); + if (campaignDetails?.status == campaignStatuses.inprogress) { + logger.info("Campaign Already In Progress and Mapped"); + } else { + sortCampaignDetails(requestBody?.Campaign?.CampaignDetails); + correctParentValues(requestBody?.Campaign?.CampaignDetails); + // Create related resources + const { tenantId } = requestBody?.Campaign; + + for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { + const resouceBody: any = { + RequestInfo: requestBody.RequestInfo, + }; + var { projectId, startDate, endDate, resources } = campaignDetails; + startDate = parseInt(startDate); + endDate = parseInt(endDate); + await createRelatedEntity( + resources, + tenantId, + projectId, + startDate, + endDate, + resouceBody + ); + } } - await createRelatedEntity( - createRelatedEntityArray, - requestBody?.CampaignDetails, - requestBody - ); } /** @@ -1196,7 +932,7 @@ async function confirmBoundaryParentCreation(request: any, code: any) { var boundaryFound = false; const header = { ...defaultheader, - // cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes.replace(/’/g, '') || ''}${params?.includeChildren || ''}`, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, } while (!boundaryFound && retry >= 0) { const response = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, searchBody, params, undefined, undefined, header); @@ -1239,7 +975,7 @@ async function createBoundaryRelationship(request: any, boundaryMap: Map<{ key: }; const header = { ...defaultheader, - // cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, } const boundaryRelationshipResponse = await httpRequest(url, request.body, params, undefined, undefined, header); @@ -1270,7 +1006,7 @@ async function createBoundaryRelationship(request: any, boundaryMap: Map<{ key: logger.info(`Boundary relationship created for boundaryType :: ${boundaryType} & boundaryCode :: ${boundaryCode} `); const newRequestBody = JSON.parse(JSON.stringify(request.body)); - activityMessage.push(await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, response, request?.body?.ResourceDetails?.type, `${config.host.boundaryHost}${config.paths.boundaryRelationshipCreate}`, response?.statusCode)); + activityMessage.push(await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, response, request?.body?.ResourceDetails?.type, url, response?.statusCode)); } catch (error) { // Log the error and rethrow to be caught by the outer try...catch block logger.error(`Error creating boundary relationship for boundaryType :: ${boundaryType} & boundaryCode :: ${boundaryCode} :: `, error); @@ -1320,12 +1056,12 @@ async function callMdmsData( ], }, }; - const url = config.host.mdmsV2 + config.paths.mdms_v1_search; + const url = config.host.mdms + config.paths.mdms_v1_search; const response = await httpRequest(url, requestBody, { tenantId: tenantId }); return response; } -function enrichSchema(data: any, properties: any, required: any, columns: any, unique: any, columnsNotToBeFreezed: any, columnsToBeFreezed: any, columnsToHide: any, errorMessage: any) { +function enrichSchema(data: any, properties: any, required: any, columns: any, unique: any, columnsNotToBeFreezed: any, errorMessage: any) { // Sort columns based on orderNumber, using name as tie-breaker if orderNumbers are equal columns.sort((a: any, b: any) => { @@ -1354,19 +1090,15 @@ function enrichSchema(data: any, properties: any, required: any, columns: any, u data.unique = unique; data.errorMessage = errorMessage; data.columnsNotToBeFreezed = columnsNotToBeFreezed; - data.columnsToBeFreezed = columnsToBeFreezed; - data.columnsToHide = columnsToHide; } -function convertIntoSchema(data: any, isUpdate: boolean) { +function convertIntoSchema(data: any) { const properties: any = {}; const errorMessage: any = {}; const required: any[] = []; - let columns: any[] = []; + const columns: any[] = []; const unique: any[] = []; const columnsNotToBeFreezed: any[] = []; - const columnsToBeFreezed: any[] = []; - const columnsToHide: any[] = []; for (const propType of ['enumProperties', 'numberProperties', 'stringProperties']) { if (data.properties[propType] && Array.isArray(data.properties[propType]) && data.properties[propType]?.length > 0) { @@ -1387,40 +1119,13 @@ function convertIntoSchema(data: any, isUpdate: boolean) { if (!property?.freezeColumn || property?.freezeColumn == false) { columnsNotToBeFreezed.push(property?.name); } - if (property?.freezeColumn) { - columnsToBeFreezed.push(property?.name); - } - if (property?.hideColumn) { - columnsToHide.push(property?.name); - } // If orderNumber is missing, default to a very high number - if (isUpdate) { - columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 }); - } - else { - if (!property?.isUpdate) { - columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 }); - } - } + columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 }); } } } - - const descriptionToFieldMap: Record = {}; - - for (const [key, field] of Object.entries(properties)) { - // Cast field to `any` since it is of type `unknown` - const typedField = field as any; - - if (typedField.isRequired) { - descriptionToFieldMap[typedField.description] = key; - } - } - data.descriptionToFieldMap = descriptionToFieldMap; - - - enrichSchema(data, properties, required, columns, unique, columnsNotToBeFreezed, columnsToBeFreezed, columnsToHide, errorMessage); + enrichSchema(data, properties, required, columns, unique, columnsNotToBeFreezed, errorMessage); return data; } @@ -1429,7 +1134,6 @@ function convertIntoSchema(data: any, isUpdate: boolean) { async function callMdmsTypeSchema( request: any, tenantId: string, - isUpdate: boolean, type: any, campaignType = "all" ) { @@ -1453,7 +1157,7 @@ async function callMdmsTypeSchema( if (!response?.mdms?.[0]?.data) { throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during schema search"); } - return convertIntoSchema(response?.mdms?.[0]?.data, isUpdate); + return convertIntoSchema(response?.mdms?.[0]?.data); } async function getMDMSV1Data(request: any, moduleName: string, masterName: string, tenantId: string) { @@ -1483,10 +1187,5 @@ export { getTargetSheetDataAfterCode, callMdmsData, getMDMSV1Data, - callMdmsTypeSchema, - getSheetDataFromWorksheet, - createProjectStaffHelper, - createProjectFacilityHelper, createProjectResourceHelper, - createAndUploadJsonFile, - getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement -}; + callMdmsTypeSchema +} diff --git a/health-services/project-factory/src/server/api/healthApis.ts b/health-services/project-factory/src/server/api/healthApis.ts deleted file mode 100644 index 0a2b0c8b0de..00000000000 --- a/health-services/project-factory/src/server/api/healthApis.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { httpRequest } from "../utils/request"; -import { defaultRequestInfo } from "./coreApis"; -import config from "../config"; -import { throwError } from "../utils/genericUtils"; -import { logger } from "../utils/logger"; - -export async function fetchProductVariants(pvarIds: string[]) { - const CHUNK_SIZE = 100; - const allProductVariants: any[] = []; - const params: any = { limit: CHUNK_SIZE, offset: 0, tenantId: defaultRequestInfo?.RequestInfo?.userInfo?.tenantId }; - - for (let i = 0; i < pvarIds.length; i += CHUNK_SIZE) { - const chunk = pvarIds.slice(i, i + CHUNK_SIZE); - try { - const response = await httpRequest( - config.host.productHost + config.paths.productVariantSearch, - { ProductVariant: { id: chunk }, ...defaultRequestInfo }, - params - ); - allProductVariants.push(...response?.ProductVariant || []); - } catch (error: any) { - logger.error("Error during product variant fetch"); - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", `Some error occurred while fetching product variants. ${error?.message}`); - } - } - - return allProductVariants; // Return the fetched product variants -} diff --git a/health-services/project-factory/src/server/api/microplanApis.ts b/health-services/project-factory/src/server/api/microplanApis.ts deleted file mode 100644 index 0dc0bcb97eb..00000000000 --- a/health-services/project-factory/src/server/api/microplanApis.ts +++ /dev/null @@ -1,124 +0,0 @@ -import config from "../config"; // Import configuration settings -import { httpRequest } from "../utils/request"; // Import httpRequest function for making HTTP requests -import { logger } from "../utils/logger"; // Import logger for logging information and errors -import { defaultRequestInfo } from "./coreApis"; // Import default request information - -/** - * Searches for facilities associated with a specific plan configuration. - * @param planConfigId The unique identifier for the plan configuration. - * @param tenantId The tenant identifier for which the search is performed. - * @returns The response containing facility details for the specified plan configuration. - */ -export const searchPlanFacility = async ( - planConfigId: string, - tenantId: string -) => { - const searchBody = { - PlanFacilitySearchCriteria: { - tenantId: tenantId, - planConfigurationId: planConfigId, - }, - ...defaultRequestInfo, // Include default request metadata - }; - logger.info( - `Received a search request for plan facility with ID: ${planConfigId}` - ); - const planFacilityResponse = await httpRequest( - config.host.planServiceHost + config.paths.planFacilitySearch, // Construct the request URL - searchBody // Pass the request body - ); - return planFacilityResponse?.PlanFacility; // Return the response from the facility search -}; - -/** - * Searches for plans based on configuration, tenant, and boundaries. - * @param planConfigId The unique identifier for the plan configuration. - * @param tenantId The tenant identifier for which the search is performed. - * @param boundaries The jurisdiction or boundary information for the search. - * @returns The response containing plan details for the specified criteria. - */ -export const searchPlan = async ( - planConfigId: string, - tenantId: string, - limit:number=1 -) => { - const searchBody = { - PlanSearchCriteria: { - tenantId: tenantId, - active: true, // Search only active plans - // jurisdiction: boundaries, // Specify jurisdiction for the search - planConfigurationId: planConfigId, - limit: limit, // Limit the response to 1 result - offset: 0, // Start from the first result - }, - ...defaultRequestInfo, // Include default request metadata - }; - logger.info( - `Received a search request for plans with ID: ${planConfigId}` - ); - const planResponse = await httpRequest( - config.host.planServiceHost + config.paths.planSearch, // Construct the request URL - searchBody // Pass the request body - ); - return planResponse?.Plan; // Return the response from the plan search -}; - -/** - * Searches for census data related to a specific plan configuration and boundary codes. - * @param planConfigId The unique identifier for the plan configuration. - * @param tenantId The tenant identifier for which the search is performed. - * @param boundaryCodes The area codes defining the search boundaries. - * @returns The response containing census details for the specified criteria. - */ -export const searchPlanCensus = async ( - planConfigId: string, - tenantId: string, - limit:number=1 -) => { - const searchBody = { - CensusSearchCriteria: { - tenantId: tenantId, - source: planConfigId, // Use planConfigId as the source of the census data - // areaCodes: boundaryCodes, // Specify area codes for the search - offset:0, - limit:limit, - }, - - ...defaultRequestInfo, // Include default request metadata - }; - logger.info( - `Received a search request for census data with ID: ${planConfigId}` - ); - const planCensusResponse = await httpRequest( - config.host.censusServiceHost + config.paths.censusSearch, // Construct the request URL - searchBody // Pass the request body - ); - return planCensusResponse?.Census; // Return the response from the census search -}; - -/** - * Searches for plan configuration details based on configuration ID and tenant. - * @param planConfigId The unique identifier for the plan configuration. - * @param tenantId The tenant identifier for which the search is performed. - * @returns The response containing configuration details for the specified plan configuration. - */ -export const searchPlanConfig = async ( - planConfigId: string, - tenantId: string -) => { - const searchBody = { - PlanConfigurationSearchCriteria: { - tenantId: tenantId, - id: planConfigId, // Specify the plan configuration ID - }, - ...defaultRequestInfo, // Include default request metadata - }; - logger.info( - `Received a search request for plan configuration with ID: ${planConfigId}` - ); - const planConfigResponse = await httpRequest( - config.host.planServiceHost + config.paths.planConfigSearch, // Construct the request URL - searchBody // Pass the request body - ); - return planConfigResponse; // Return the response from the plan configuration search -}; diff --git a/health-services/project-factory/src/server/app.ts b/health-services/project-factory/src/server/app.ts index f662b76d104..a51c4ab15bd 100644 --- a/health-services/project-factory/src/server/app.ts +++ b/health-services/project-factory/src/server/app.ts @@ -1,21 +1,10 @@ -import express from "express"; -import * as bodyParser from "body-parser"; -import config from "./config"; -import { requestMiddleware } from "./utils/middlewares"; -import { - errorLogger, - errorResponder, - invalidPathHandler, -} from "./utils/genericUtils"; -import { tracingMiddleware } from "./tracing"; -import { createProxyMiddleware } from "http-proxy-middleware"; -import * as v8 from "v8"; -import { logger } from "./utils/logger"; - -const printMemoryInMB = (memoryInBytes: number) => { - const memoryInMB = memoryInBytes / (1024 * 1024); // Convert bytes to MB - return `${memoryInMB.toFixed(2)} MB`; -}; +import express from 'express'; +import * as bodyParser from 'body-parser'; +import config from './config'; +import { requestMiddleware } from './utils/middlewares'; +import { errorLogger, errorResponder, invalidPathHandler } from './utils/genericUtils'; +import { tracingMiddleware } from './tracing'; +import { createProxyMiddleware } from 'http-proxy-middleware'; class App { public app: express.Application; @@ -28,43 +17,21 @@ class App { this.initializeMiddlewares(); this.initializeControllers(controllers); this.app.use(invalidPathHandler); - - // Global error handling for uncaught exceptions - process.on("uncaughtException", (err) => { - console.error("Unhandled Exception:", err); - }); - - // Global error handling for unhandled promise rejections - process.on("unhandledRejection", (reason, promise) => { - console.error("Unhandled Rejection at:", promise, "reason:", reason); - }); } private initializeMiddlewares() { - this.app.use( - bodyParser.json({ limit: config.app.incomingRequestPayloadLimit }) - ); - this.app.use( - bodyParser.urlencoded({ - limit: config.app.incomingRequestPayloadLimit, - extended: true, - }) - ); this.app.use(bodyParser.json()); this.app.use(tracingMiddleware); this.app.use(requestMiddleware); this.app.use(errorLogger); this.app.use(errorResponder); - this.app.use( - "/tracing", - createProxyMiddleware({ - target: "http://localhost:16686", - changeOrigin: true, - pathRewrite: { - "^/tracing": "/", - }, - }) - ); + this.app.use('/tracing', createProxyMiddleware({ + target: 'http://localhost:16686', + changeOrigin: true, + pathRewrite: { + '^/tracing': '/', + }, + })); } private initializeControllers(controllers: any) { @@ -75,34 +42,7 @@ class App { public listen() { this.app.listen(this.port, () => { - logger.info(`App listening on the port ${this.port}`); - // Add periodic monitoring - setInterval(() => { - const stats = v8.getHeapStatistics(); - const usedHeapSize = stats.used_heap_size; - const heapLimit = stats.heap_size_limit; - - logger.debug( - JSON.stringify({ - "Heap Usage": { - used: printMemoryInMB(usedHeapSize), - limit: printMemoryInMB(heapLimit), - percentage: ((usedHeapSize / heapLimit) * 100).toFixed(2), - }, - }) - ); - - // Alert if memory usage is above 80% - if (usedHeapSize / heapLimit > 0.8) { - logger.warn("High memory usage detected"); - } - }, 5 * 60 * 1000); // Every 5 minutes - logger.info( - "Current App's Heap Configuration Total Available :", - printMemoryInMB(v8.getHeapStatistics()?.total_available_size), - " max limit set to : ", - printMemoryInMB(v8.getHeapStatistics()?.heap_size_limit) - ); + console.log(`App listening on the port ${this.port}`); }); } } diff --git a/health-services/project-factory/src/server/config/constants.ts b/health-services/project-factory/src/server/config/constants.ts index 73178392f23..fffa89a7c87 100644 --- a/health-services/project-factory/src/server/config/constants.ts +++ b/health-services/project-factory/src/server/config/constants.ts @@ -10,8 +10,7 @@ export const CONSTANTS: any = { INVALID_PAGINATION: "Invalid pagination", KAFKA_ERROR: "Some error occured in kafka", SCHEMA_ERROR: " Schema related error", - RESPONSE_NOT_FOUND_ERROR: "Response not found", - GENERATE_ERROR: "Error while generating user/facility/boundary" + RESPONSE_NOT_FOUND_ERROR: "Response not found" }, FILE: { INVALID_FILE: "No download URL returned for the given fileStoreId", @@ -33,12 +32,7 @@ export const CONSTANTS: any = { CAMPAIGN_NOT_FOUND: "Campaign not found", GENERATION_REQUIRE: "First generate then download", RESOURCE_CREATION_ERROR: "Some error occured during resource creation", - CAMPAIGN_NAME_ERROR: "Campaign name already exists", - CAMPAIGN_NAME_NOT_MATCHING_PARENT_ERROR: "Campaign name different from parent Campaign", - CAMPAIGN_ALREADY_MAPPED: "Campaign is already mapped", - PARENT_CAMPAIGN_ERROR: "Parent Camapign error ", - INVALID_RESOURCE_DISTRIBUTION_STRATEGY: "Invalid resource distribution strategy", - RESOURCES_CONSOLIDATION_ERROR : "Error while consolidating resources in Campaign Update Flow " + CAMPAIGN_NAME_ERROR: "Campaign name already exists" }, BOUNDARY: { BOUNDARY_DATA_NOT_FOUND: "No boundary data found in the system.", @@ -49,9 +43,7 @@ export const CONSTANTS: any = { BOUNDARY_ENTITY_CREATE_ERROR: "Some error occured during boundary entity creation", BOUNDARY_RELATIONSHIP_CREATE_ERROR: "Some error occured during boundary relationship creation", BOUNDARY_TARGET_ERROR: "Target either not present or invalid value", - BOUNDARY_CONFIRMATION_FAILED: "Error in boundary creation and persistence", - BOUNDARY_SHEET_UPLOADED_INVALID_ERROR: "Error in the boundary data uploaded", - BOUNDARY_SHEET_FIRST_COLUMN_INVALID_ERROR: "First Column Of Boundary Sheet uploaded should be unique as it is the root of hierarchy" + BOUNDARY_CONFIRMATION_FAILED: "Error in boundary creation and persistence" }, PROJECT: { PROJECT_CREATION_FAILED: "Error occured in project creation", @@ -59,17 +51,10 @@ export const CONSTANTS: any = { PROJECT_UPDATE_ERROR: "Error occured during project update , check projectId", PROJECT_CREATION_ERROR: "Some error occured during project creation", PROJECT_CONFIRMATION_FAILED: "Error occured in project creation and peristence", - PROJECT_STAFF_SEARCH_ERROR: "Error occured during project search , check projectId and staffId", - PROJECT_FACILITY_SEARCH_ERROR: "Error occured during project search , check projectId and facilityId", - PROJECT_FACILITY_DELETE_ERROR: "Error occured while deleting project facility mapping", - PROJECT_STAFF_DELETE_ERROR: "Error occured while deleting project staff mapping" }, MDMS: { INVALID_README_CONFIG: "Invalid readme config", MDMS_DATA_NOT_FOUND_ERROR: "Mdms Data not present" - }, - DATA:{ - DATA_CREATE_ERROR : "Error while creating resource data" } } } @@ -123,40 +108,7 @@ export const generatedResourceStatuses: any = { expired: "expired" } -export const processTrackTypes = { - validation: "validation", - triggerResourceCreation: "trigger-resource-creation", - facilityCreation: "facility-creation", - staffCreation: "staff-creation", - targetAndDeliveryRulesCreation: "target-and-delivery-rules-creation", - confirmingResourceCreation: "confirming-resource-creation", - prepareResourceForMapping: "prepare-resource-for-mapping", - validateMappingResource: "validate-mapping-resource", - staffMapping: "staff-mapping", - resourceMapping: "resource-mapping", - facilityMapping: "facility-mapping", - campaignCreation: "campaign-creation", - error: "error" -} - -export const processTrackForUi = [ - processTrackTypes.facilityCreation, - processTrackTypes.staffCreation, - processTrackTypes.targetAndDeliveryRulesCreation, - processTrackTypes.staffMapping, - processTrackTypes.resourceMapping, - processTrackTypes.facilityMapping, - processTrackTypes.campaignCreation, - processTrackTypes.error -]; - -export const processTrackStatuses = { - inprogress: "inprogress", - completed: "completed", - toBeCompleted: "toBeCompleted", - failed: "failed", -} // Retrieves the error object containing the error code, message, and notFound flag. export const getErrorCodes = (module: string, key: string): Error => { // Retrieve the error message from the CONSTANTS object @@ -171,4 +123,4 @@ export const getErrorCodes = (module: string, key: string): Error => { notFound: true, message: message } -} \ No newline at end of file +} diff --git a/health-services/project-factory/src/server/config/createAndSearch.ts b/health-services/project-factory/src/server/config/createAndSearch.ts index 31f801d7e59..d89c45b7606 100644 --- a/health-services/project-factory/src/server/config/createAndSearch.ts +++ b/health-services/project-factory/src/server/config/createAndSearch.ts @@ -8,7 +8,7 @@ const createAndSearch: any = { } ], boundaryValidation: { - column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" }, sheetSchema: { "$schema": "http://json-schema.org/draft-07/schema#", @@ -132,151 +132,14 @@ const createAndSearch: any = { searchPath: "Facilities" } }, - "facilityMicroplan": { - requiresToSearchFromSheet: [ - { - sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", - searchPath: "Facility.id" - } - ], - boundaryValidation: { - column: "HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN" - }, - sheetSchema: { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "FacilityTemplateSchema", - "type": "object", - "properties": { - "Facility Name": { - "type": "string", - "maxLength": 2000, - "minLength": 1 - }, - "Facility Type": { - // "type": "string", - "enum": ["Warehouse", "Health Facility", "Storing Resource"] - }, - "Facility Status": { - // "type": "string", - "enum": ["Temporary", "Permanent"] - }, - "Capacity": { - "type": "number", - "minimum": 1, - "maximum": 100000000 - } - }, - "required": [ - "Facility Name", - "Facility Type", - "Facility Status", - "Capacity" - ], - "unique": [ - "Facility Name" - ] - }, - uniqueIdentifier: "id", - uniqueIdentifierColumn: "A", - activeColumn: "F", - activeColumnName: "HCM_ADMIN_CONSOLE_FACILITY_USAGE_MICROPLAN", - uniqueIdentifierColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", - matchEachKey: true, - parseArrayConfig: { - sheetName: "HCM_ADMIN_CONSOLE_FACILITIES", - parseLogic: [ - { - sheetColumn: "A", - sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", - resultantPath: "id", - type: "string" - }, - { - sheetColumn: "B", - sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_NAME_MICROPLAN", - resultantPath: "name", - type: "string" - }, - { - sheetColumn: "C", - sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_TYPE_MICROPLAN", - resultantPath: "usage", - type: "string" - }, - { - sheetColumn: "D", - sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_STATUS_MICROPLAN", - resultantPath: "isPermanent", - type: "boolean", - conversionCondition: { - "Permanent": "true", - "Temporary": "" - } - }, - { - sheetColumn: "E", - sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN", - resultantPath: "storageCapacity", - type: "number" - }, - { - sheetColumn: "J", - sheetColumnName: "HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN" - } - ], - tenantId: { - getValueViaPath: "ResourceDetails.tenantId", - resultantPath: "tenantId" - } - }, - createBulkDetails: { - limit: 50, - createPath: "Facilities", - url: config.host.facilityHost + "facility/v1/bulk/_create" - }, - searchDetails: { - searchElements: [ - { - keyPath: "tenantId", - getValueViaPath: "ResourceDetails.tenantId", - isInParams: true, - isInBody: false, - }, - { - keyPath: "Facility", - isInParams: false, - isInBody: true, - } - ], - searchLimit: { - keyPath: "limit", - value: "200", - isInParams: true, - isInBody: false, - }, - searchOffset: { - keyPath: "offset", - value: "0", - isInParams: true, - isInBody: false, - }, - url: config.host.facilityHost + "facility/v1/_search", - searchPath: "Facilities" - } - }, "boundary": { parseArrayConfig: { sheetName: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", } }, "user": { - requiresToSearchFromSheet: [ - { - sheetColumnName: "UserService Uuids", - searchPath: "user.mobileNumber" - }], boundaryValidation: { - column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" }, sheetSchema: { "$schema": "http://json-schema.org/draft-07/schema#", @@ -354,10 +217,8 @@ const createAndSearch: any = { } }, uniqueIdentifier: "user.userServiceUuid", - uniqueIdentifierColumn: "I", + uniqueIdentifierColumn: "H", uniqueIdentifierColumnName: "UserService Uuids", - activeColumn: "F", - activeColumnName: "HCM_ADMIN_CONSOLE_USER_USAGE", createBulkDetails: { limit: 50, createPath: "Employees", @@ -395,14 +256,6 @@ const createAndSearch: any = { boundaryValidation: { column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE" } - }, - "boundaryManagement": { - parseArrayConfig: { - sheetName: "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", - }, - boundaryValidation: { - column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE" - } } } diff --git a/health-services/project-factory/src/server/config/index.ts b/health-services/project-factory/src/server/config/index.ts index 862ac0a9059..07286afac9e 100644 --- a/health-services/project-factory/src/server/config/index.ts +++ b/health-services/project-factory/src/server/config/index.ts @@ -12,41 +12,29 @@ if (!HOST) { const getDBSchemaName = (dbSchema = "") => { - // return "health"; return dbSchema ? (dbSchema == "egov" ? "public" : dbSchema) : "public"; } // Configuration object containing various environment variables const config = { - batchSize:100, - cacheTime: 300, - isProduction: process.env ? true : false, - token: "", // add default token if core services are not port forwarded - enableDynamicTemplateFor: process.env.ENABLE_DYNAMIC_TEMPLATE_FOR || "", - isCallGenerateWhenDeliveryConditionsDiffer: (process.env.IS_CALL_GENERATE_WHEN_DELIVERY_CONDITIONS_DIFFER === "true") || false, - prefixForMicroplanCampaigns: "MP", - excludeHierarchyTypeFromBoundaryCodes: (process.env.EXCLUDE_HIERARCHY_TYPE_FROM_BOUNDARY_CODES === "true") || false, - excludeBoundaryNameAtLastFromBoundaryCodes: (process.env.EXCLUDE_BOUNDARY_NAME_AT_LAST_FROM_BOUNDARY_CODES === "true") || false, masterNameForSchemaOfColumnHeaders: "adminSchema", - masterNameForSplitBoundariesOn: "HierarchySchema", boundary: { boundaryCode: process.env.BOUNDARY_CODE_HEADER_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", - boundaryCodeMandatory: 'HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY', - boundaryCodeOld: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", boundaryTab: process.env.BOUNDARY_TAB_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", + // Default criteria for generating different tabs + generateDifferentTabsOnBasisOf: process.env.SPLIT_BOUNDARIES_ON || "ADMIN_DISTRITO", // default configurable number of data of boundary type on which generate different tabs numberOfBoundaryDataOnWhichWeSplit: process.env.SPLIT_BOUNDARIES_ON_LENGTH || "2", boundaryRelationShipDelay: 3500 }, facility: { facilityTab: process.env.FACILITY_TAB_NAME || "HCM_ADMIN_CONSOLE_FACILITIES", - facilityCodeColumn : "HCM_ADMIN_CONSOLE_FACILITY_CODE", - facilityType : "facility" + facilitySchemaMasterName: process.env.FACILITY_SCHEMA_MASTER || "facilitySchema", }, user: { userTab: process.env.USER_TAB_NAME || "HCM_ADMIN_CONSOLE_USER_LIST", + userSchemaMasterName: process.env.USER_SCHEMA_MASTER || "userSchema", userDefaultPassword: process.env.USER_DEFAULT_PASSWORD || "eGov@123", userPasswordAutoGenerate: process.env.USER_PASSWORD_AUTO_GENERATE || "true", - mapUserViaCommonParent: process.env.MAP_USER_VIA_COMMON_PARENT || false, }, cacheValues: { cacheEnabled: process.env.CACHE_ENABLED, @@ -56,7 +44,7 @@ const config = { kafka: { // Kafka topics KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "save-project-campaign-details", - KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "update-project-campaign-details", + KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "update-project-campaign-details", KAFKA_START_CAMPAIGN_MAPPING_TOPIC: process.env.KAFKA_START_CAMPAIGN_MAPPING_TOPIC || "start-campaign-mapping", KAFKA_UPDATE_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_UPDATE_CAMPAIGN_DETAILS_TOPIC || "update-campaign-details", KAFKA_CREATE_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC || "create-resource-details", @@ -66,8 +54,6 @@ const config = { KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC || "create-generated-resource-details", KAFKA_SAVE_PROCESS_TRACK_TOPIC: process.env.KAFKA_SAVE_PROCESS_TRACK_TOPIC || "save-process-track", KAFKA_UPDATE_PROCESS_TRACK_TOPIC: process.env.KAFKA_UPDATE_PROCESS_TRACK_TOPIC || "update-process-track", - KAFKA_SAVE_PLAN_FACILITY_TOPIC: process.env.KAFKA_SAVE_PLAN_FACILITY_TOPIC || "project-factory-save-plan-facility", - KAFKA_TEST_TOPIC: "test-topic-project-factory", }, // Database configuration @@ -88,17 +74,12 @@ const config = { host: HOST, contextPath: process.env.CONTEXT_PATH || "/project-factory", logLevel: process.env.APP_LOG_LEVEL || "debug", - debugLogCharLimit: process.env.APP_MAX_DEBUG_CHAR ? Number(process.env.APP_MAX_DEBUG_CHAR) : 1000, - defaultTenantId: process.env.DEFAULT_TENANT_ID || "mz", - // incomingRequestPayloadLimit : process.env.REQUEST_PAYLOAD_LIMIT || "2mb" @ashish add this key and config helm chart values - incomingRequestPayloadLimit: "2mb" + debugLogCharLimit: process.env.APP_MAX_DEBUG_CHAR ? Number(process.env.APP_MAX_DEBUG_CHAR) : 1000 }, localisation: { defaultLocale: process.env.LOCALE || "en_MZ", - boundaryPrefix: "hcm-boundary", - localizationModule: process.env.LOCALIZATION_MODULE || "hcm-admin-schemas", - localizationWaitTimeInBoundaryCreation: parseInt(process.env.LOCALIZATION_WAIT_TIME_IN_BOUNDARY_CREATION || "30000"), - localizationChunkSizeForBoundaryCreation: parseInt(process.env.LOCALIZATION_CHUNK_SIZE_FOR_BOUNDARY_CREATION || "2000"), + boundaryPrefix: "rainmaker-boundary", + localizationModule: process.env.LOCALIZATION_MODULE || "rainmaker-hcm-admin-schemas", }, // targetColumnsForSpecificCampaigns: { // bedNetCampaignColumns: ["HCM_ADMIN_CONSOLE_TARGET"], @@ -123,14 +104,12 @@ const config = { hrmsHost: process.env.EGOV_HRMS_HOST || "https://unified-dev.digit.org/", localizationHost: process.env.EGOV_LOCALIZATION_HOST || "https://unified-dev.digit.org/", healthIndividualHost: process.env.EGOV_HEALTH_INDIVIDUAL_HOST || "https://unified-dev.digit.org/", - planServiceHost: process.env.EGOV_PLAN_SERVICE_HOST || "https://unified-dev.digit.org/", - censusServiceHost: process.env.EGOV_CENSUS_HOST ||"https://unified-dev.digit.org/", }, + }, // Paths for different services paths: { filestore: process.env.FILE_STORE_SERVICE_END_POINT || "filestore/v1/files", - filestorefetch: "filestore/v1/files/url", - mdms_v2_search: process.env.EGOV_MDMS_V2_SEARCH_ENDPOINT || "mdms-v2/v2/_search", - mdms_v1_search: process.env.EGOV_MDMS_V1_SEARCH_ENDPOINT || "mdms-v2/v1/_search", + mdms_search: process.env.EGOV_MDMS_SEARCH_ENDPOINT || "egov-mdms-service/v2/_search", + mdms_v1_search: process.env.EGOV_MDMS_V1_SEARCH_ENDPOINT || "egov-mdms-service/v1/_search", idGen: process.env.EGOV_IDGEN_PATH || "egov-idgen/id/_generate", mdmsSchema: process.env.EGOV_MDMS_SCHEMA_PATH || "egov-mdms-service/schema/v1/_search", boundaryRelationship: process.env.EGOV_BOUNDARY_RELATIONSHIP_SEARCHPATH || "boundary-service/boundary-relationships/_search", @@ -152,38 +131,28 @@ const config = { localizationSearch: process.env.EGOV_LOCALIZATION_SEARCH || "localization/messages/v1/_search", localizationCreate: "localization/messages/v1/_upsert", projectTypeSearch: "project-factory/v1/project-type/search", - cacheBurst: process.env.CACHE_BURST || "localization/messages/cache-bust", boundaryRelationshipCreate: "boundary-service/boundary-relationships/_create", + mdmsV2SchemaSearch: "mdms-v2/schema/v1/_search", + mdms_v2_search: "mdms-v2/v2/_search", healthIndividualSearch: process.env.EGOV_HEALTH_INDIVIDUAL_SEARCH || "health-individual/v1/_search", - projectFacilitySearch: process.env.EGOV_HEALTH_PROJECT_FACILITY_SEARCH || "health-project/facility/v1/_search", - projectStaffSearch: process.env.EGOV_HEALTH_PROJECT_STAFF_SEARCH || "health-project/staff/v1/_search", - projectFacilityDelete: process.env.EGOV_HEALTH_PROJECT_FACILITY_BULK_DELETE || "health-project/facility/v1/bulk/_delete", - projectStaffDelete: process.env.EGOV_HEALTH_PROJECT_STAFF_BULK_DELETE || "health-project/staff/v1/bulk/_delete", - planFacilitySearch: process.env.EGOV_PLAN_FACILITY_SEARCH || "plan-service/plan/facility/_search", - planConfigSearch: process.env.EGOV_PLAN_FACILITY_CONFIG_SEARCH || "plan-service/config/_search", - planSearch: process.env.EGOV_PLAN_SEARCH || "plan-service/plan/_search", - censusSearch: process.env.EGOV_CENSUS_SEARCH || "census-service/_search" }, + }, // Values configuration values: { //module name unfrozeTillRow: process.env.UNFROZE_TILL_ROW || "10000", unfrozeTillColumn: process.env.UNFROZE_TILL_COLUMN || "50", moduleName: process.env.MODULE_NAME || "HCM-ADMIN-CONSOLE", - readMeTab: process.env.READ_ME_TAB || "HCM_README_SHEETNAME", + readMeTab: "HCM_README_SHEETNAME", userMainBoundary: "mz", userMainBoundaryType: "Country", idgen: { format: process.env.CMP_IDGEN_FORMAT || "CMP-[cy:yyyy-MM-dd]-[SEQ_EG_CMP_ID]", - idName: process.env.CMP_IDGEN_IDNAME || "campaign.number", - idNameForUserNameGeneration: "username.name", - formatForUserName: "USR-[SEQ_EG_USER_NAME]" + idName: process.env.CMP_IDGEN_IDNAME || "campaign.number" }, matchFacilityData: false, retryCount: process.env.CREATE_RESOURCE_RETRY_COUNT || "3", notCreateUserIfAlreadyThere: process.env.NOT_CREATE_USER_IF_ALREADY_THERE || false, - maxHttpRetries: process.env.MAX_HTTP_RETRIES || "4", - skipResourceCheckValidationBeforeCreateForLocalTesting:false, // can be set to true for local development - autoRetryIfHttpError: process.env.AUTO_RETRY_IF_HTTP_ERROR || "socket hang up" // can be retry if there is any error for which default retry can be set + maxHttpRetries: process.env.MAX_HTTP_RETRIES || "4" } }; // Exporting getErrorCodes function and config object diff --git a/health-services/project-factory/src/server/config/models/SearchCriteria.ts b/health-services/project-factory/src/server/config/models/SearchCriteria.ts index d5acc896484..54d30a7d0e1 100644 --- a/health-services/project-factory/src/server/config/models/SearchCriteria.ts +++ b/health-services/project-factory/src/server/config/models/SearchCriteria.ts @@ -17,9 +17,6 @@ export const searchCriteriaSchema = { }, "status": { "type": "string" - }, - "hierarchyType": { - "type": "string" } }, "required": ["tenantId"], diff --git a/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts b/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts index 61de751134b..873d2b5d034 100644 --- a/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts +++ b/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts @@ -19,7 +19,7 @@ export const campaignDetailsDraftSchema = { }, "action": { "type": "string", - "enum": ["create", "draft", "retry"], + "enum": ["create", "draft"], "maxLength": 64, "minLength": 1 }, @@ -92,9 +92,6 @@ export const campaignDetailsDraftSchema = { }, "additionalDetails": { "type": "object" - }, - "isActive":{ - "type":"boolean" } }, "required": ["tenantId", "campaignName", "hierarchyType"] diff --git a/health-services/project-factory/src/server/config/models/createRequestSchema.ts b/health-services/project-factory/src/server/config/models/createRequestSchema.ts index 2f9b36bc136..ed56e706d16 100644 --- a/health-services/project-factory/src/server/config/models/createRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/createRequestSchema.ts @@ -4,7 +4,7 @@ export const createRequestSchema = { "properties": { "type": { "type": "string", - "enum": ["boundary", "facility", "user", "boundaryWithTarget", "facilityMicroplan","boundaryManagement", "boundaryGeometryManagement"] + "enum": ["boundary", "facility", "user", "boundaryWithTarget"] }, "tenantId": { "type": "string", @@ -32,9 +32,6 @@ export const createRequestSchema = { }, "additionalDetails": { "type": "object" - }, - "isActive":{ - "type":"boolean" } }, "required": ["type", "tenantId", "fileStoreId", "action", "hierarchyType"], diff --git a/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts index 759e3aa9d36..b47e714dac5 100644 --- a/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts @@ -5,7 +5,7 @@ export const downloadRequestSchema = { "tenantId": { "type": "string", "maxLength": 128, - "minLength": 1 + "minLength": 1, }, "type": { "type": "string", @@ -16,32 +16,20 @@ export const downloadRequestSchema = { "user", "boundary", "facilityWithBoundary", - "userWithBoundary", - "boundaryManagement", - "boundaryGeometryManagement" + "userWithBoundary" ] }, "hierarchyType": { "type": "string", "maxLength": 128, - "minLength": 1 + "minLength": 1, }, "id": { "type": "string", - "maxLength": 128, - "minLength": 1 - }, - "status": { - "type": "string", - "maxLength": 500, - "minLength": 1 - }, - "campaignId": { - "type": "string", - "maxLength": 128, - "minLength": 1 + "maxlength": 128, + "minLength": 1, } }, "required": ["tenantId", "type", "hierarchyType"], "additionalProperties": false -} \ No newline at end of file +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts index 1413905173a..cc1df4b70e6 100644 --- a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts @@ -12,11 +12,11 @@ export const generateRequestSchema = { "maxLength": 128, "minLength": 1, "enum": [ + "facility", + "user", "boundary", - "boundaryManagement", "facilityWithBoundary", - "userWithBoundary", - "boundaryGeometryManagement" + "userWithBoundary" ] }, "hierarchyType": { @@ -30,9 +30,6 @@ export const generateRequestSchema = { }, "campaignId": { "type": "string" - }, - "source": { - "type": "string", } }, "required": ["tenantId", "type", "hierarchyType", "campaignId"], diff --git a/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts b/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts index 8f4588ad79b..155e8babbc4 100644 --- a/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts +++ b/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts @@ -9,9 +9,6 @@ export const searchCampaignDetailsSchema = { "type": "string" } }, - "isActive":{ - "type":"boolean" - }, "tenantId": { "type": "string", "minLength": 1 diff --git a/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts index 1fd3e0646ea..384735fb683 100644 --- a/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts +++ b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts @@ -1,16 +1,7 @@ import * as express from "express"; -import { - createCampaignService, - createProjectTypeCampaignService, - fetchFromMicroplanService, - retryProjectTypeCampaignService, - searchProcessTracksService, - searchProjectTypeCampaignService, - updateProjectTypeCampaignService -} from "../../service/campaignManageService"; +import { createCampaignService, createProjectTypeCampaignService, searchProjectTypeCampaignService, updateProjectTypeCampaignService } from "../../service/campaignManageService"; import { logger } from "../../utils/logger"; import { errorResponder, sendResponse } from "../../utils/genericUtils"; -import { validateSearchProjectCampaignRequest } from "../../validators/campaignValidators"; @@ -31,13 +22,8 @@ class campaignManageController { this.router.post(`${this.path}/create`, this.createProjectTypeCampaign); this.router.post(`${this.path}/update`, this.updateProjectTypeCampaign); this.router.post(`${this.path}/search`, this.searchProjectTypeCampaign); - this.router.post(`${this.path}/retry`, this.retryProjectTypeCampaign); this.router.post(`${this.path}/createCampaign`, this.createCampaign); - this.router.post(`${this.path}/getProcessTrack`, this.searchProcessTracks); - this.router.post(`${this.path}/fetch-from-microplan`, this.fetchFromMicroplan); } - - /** * Handles the creation of a project type campaign. * @param request The Express request object. @@ -91,9 +77,7 @@ class campaignManageController { ) => { try { logger.info("RECEIVED A PROJECT TYPE SEARCH REQUEST"); - // Validate the search request for project type campaigns - await validateSearchProjectCampaignRequest(request); - const responseBody = await searchProjectTypeCampaignService(request?.body?.CampaignDetails); + const responseBody = await searchProjectTypeCampaignService(request); // Send response with campaign details and total count return sendResponse(response, responseBody, request); } catch (e: any) { @@ -127,58 +111,7 @@ class campaignManageController { } }; - searchProcessTracks = async ( - request: express.Request, - response: express.Response - ) => { - try { - logger.info("RECEIVED A PROCESS SEARCH REQUEST"); - const processTrack = await searchProcessTracksService(request); - // Send response with campaign details - return sendResponse(response, { processTrack }, request); - } - catch (e: any) { - console.log(e) - logger.error(String(e)) - // Handle errors and send error response - return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); - } - }; - - retryProjectTypeCampaign = async ( - request: express.Request, - response: express.Response - ) => { - try { - logger.info("RECEIVED A PROJECT TYPE RETRY REQUEST"); - const CampaignDetails = await retryProjectTypeCampaignService(request); - return sendResponse(response, { CampaignDetails }, request); - } catch (e: any) { - console.log(e) - logger.error(String(e)) - // Handle errors and send error response - return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); - } - } - - fetchFromMicroplan = async ( - request: express.Request, - response: express.Response - ) => { - try { - logger.info("RECEIVED A FETCH FROM MICROPLAN REQUEST"); - const CampaignDetails = await fetchFromMicroplanService(request); - return sendResponse(response, { CampaignDetails }, request); - } - catch (e: any) { - console.log(e) - logger.error(String(e)) - return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); - } - } - }; - export default campaignManageController; diff --git a/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts index 1c41ba84614..3591c1c016c 100644 --- a/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts +++ b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts @@ -3,7 +3,6 @@ import { logger } from "../../utils/logger"; import { httpRequest } from "../../utils/request"; import config from "../../config/index"; import { convertLocalisationResponseToMap } from "../../utils/localisationUtils"; -import { defaultRequestInfo } from "../../api/coreApis"; let cachedResponse = {}; @@ -16,7 +15,7 @@ class Localisation { // Hold the single instance of the class private static instance: Localisation; constructor() { - this.localizationHost = config.host.localizationHost; + this.localizationHost = config.host.localizationHost } // Public method to provide access to the single instance public static getInstance(): Localisation { @@ -37,13 +36,12 @@ class Localisation { public getLocalisedData: any = async ( module: string, locale: string, - tenantId: string, - overrideCache: boolean + tenantId: string ) => { logger.info( `Checks Localisation message is available in cache for module ${module}, locale ${locale}, tenantId ${tenantId}` ); - if (!this?.cachedResponse?.[`${module}-${locale}`] || overrideCache) { + if (!this?.cachedResponse?.[`${module}-${locale}`]) { logger.info(`Not found in cache`); await this.fetchLocalisationMessage(module, locale, tenantId); } @@ -83,34 +81,6 @@ class Localisation { ); cachedResponse = { ...this.cachedResponse }; }; - - // Calls the cache burst API of localization - public cacheBurst = async ( - ) => { - logger.info(`Calling localization cache burst api`); - const RequestInfo = defaultRequestInfo; - const requestBody = { - RequestInfo - } - await httpRequest( - this.localizationHost + config.paths.cacheBurst, - requestBody) - }; - - - private checkCacheAndDeleteIfExists = (module: string, locale: "string") => { - logger.info( - `Received to checkCacheAndDeleteIfExists for module ${module}, locale ${locale}` - ); - if (this.cachedResponse?.[`${module}-${locale}`]) { - logger.info(`cache found to for module ${module}, locale ${locale}`); - if (delete this.cachedResponse?.[`${module}-${locale}`]) { - logger.info( - `cache deleted for module ${module}, locale ${locale}, since new data has been created` - ); - } - } - }; /** * Create localisation entries by sending a POST request to the localization host. @@ -128,26 +98,19 @@ class Localisation { // Construct request body with RequestInfo and localisation messages const requestBody = { RequestInfo, messages, tenantId }; // Construct URL for localization create endpoint - const url = this.localizationHost + config.paths.localizationCreate; + const url = + this.localizationHost + config.paths.localizationCreate; // Log the start of the localisation messages creation process - logger.info(`Creating the localisation messages of count ${messages?.length}`); + logger.info("Creating the localisation messages"); // Send HTTP POST request to create localisation messages await httpRequest(url, requestBody); - - messages && - messages?.length > 0 && - this.checkCacheAndDeleteIfExists( - messages?.[0]?.module, - messages?.[0]?.locale - ); // Log the completion of the localisation messages creation process logger.info("Localisation messages created successfully"); } catch (e: any) { // Log and handle any errors that occur during the process console.log(e); logger.error(String(e)); - throw new Error(e); } }; } diff --git a/health-services/project-factory/src/server/kafka/Listener.ts b/health-services/project-factory/src/server/kafka/Listener.ts index 128f99c08cb..ac91786b621 100644 --- a/health-services/project-factory/src/server/kafka/Listener.ts +++ b/health-services/project-factory/src/server/kafka/Listener.ts @@ -1,55 +1,105 @@ -import { ConsumerGroup, ConsumerGroupOptions, Message } from 'kafka-node'; +import { Message ,ConsumerGroup, ConsumerGroupOptions} from 'kafka-node'; import config from '../config'; -import { getFormattedStringForDebug, logger } from '../utils/logger'; -import { shutdownGracefully } from '../utils/genericUtils'; -import { handleCampaignMapping } from '../utils/campaignMappingUtils'; +import { getFormattedStringForDebug, logger } from '../utils/logger'; // Importing logger utility for logging +import { producer } from './Producer'; // Importing producer from the Producer module +import { processCampaignMapping } from '../utils/campaignMappingUtils'; +import { enrichAndPersistCampaignWithError } from '../utils/campaignUtils'; +import { throwError } from '../utils/genericUtils'; -// Kafka Configuration -const kafkaConfig: ConsumerGroupOptions = { - kafkaHost: config?.host?.KAFKA_BROKER_HOST, + + +// Replace with the correct Kafka broker(s) and topic name +const kafkaConfig:ConsumerGroupOptions = { + kafkaHost: config?.host?.KAFKA_BROKER_HOST, // Use the correct broker address and port groupId: 'project-factory', autoCommit: true, autoCommitIntervalMs: 5000, fromOffset: 'latest', + }; -// Topic Names -const topicNames = [ - config.kafka.KAFKA_START_CAMPAIGN_MAPPING_TOPIC, - config.kafka.KAFKA_TEST_TOPIC -]; +const topicName = config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC; + +// Create a Kafka client +// const kafkaClient = new KafkaClient(kafkaConfig); + +// Create a Kafka consumer +// const consumer = new Consumer(kafkaClient, [{ topic: topicName, partition: 0 }], { autoCommit: true }); + -// Consumer Group Initialization -const consumerGroup = new ConsumerGroup(kafkaConfig, topicNames); +const consumerGroup=new ConsumerGroup(kafkaConfig, topicName) -// Kafka Listener +// Exported listener function export function listener() { + // Set up a message event handler consumerGroup.on('message', async (message: Message) => { try { - const messageObject = JSON.parse(message.value?.toString() || '{}'); - - switch (message.topic) { - case config.kafka.KAFKA_START_CAMPAIGN_MAPPING_TOPIC: - await handleCampaignMapping(messageObject); - break; - default: - logger.warn(`Unhandled topic: ${message.topic}`); + // Parse the message value as an array of objects + const messageObject: any = JSON.parse(message.value?.toString() || '{}'); + try { + // await processCampaignMapping(messageObject); + logger.info("Received a messageObject for campaign mapping : "); + logger.debug("Message Object of campaign mapping :: " + getFormattedStringForDebug(messageObject)); + await processCampaignMapping(messageObject); + } catch (error: any) { + console.log(error) + logger.error(error) + enrichAndPersistCampaignWithError(messageObject, error) } - - logger.info(`KAFKA :: LISTENER :: Received a message from topic ${message.topic}`); - logger.debug(`KAFKA :: LISTENER :: Message: ${getFormattedStringForDebug(messageObject)}`); + logger.info(`KAFKA :: LISTENER :: Received a message`); + logger.debug(`KAFKA :: LISTENER :: message ${getFormattedStringForDebug(messageObject)}`); } catch (error) { - logger.error(`KAFKA :: LISTENER :: Error processing message: ${error}`); - console.error(error); + logger.info('KAFKA :: LISTENER :: Some Error Occurred '); // Log successful message production + logger.error(`KAFKA :: LISTENER :: Error : ${JSON.stringify(error)}`); // Log producer error + console.log(error) } }); + // Set up error event handlers consumerGroup.on('error', (err) => { - logger.error(`Consumer Error: ${err}`); - shutdownGracefully(); + console.error(`Consumer Error: ${err}`); }); consumerGroup.on('offsetOutOfRange', (err) => { - logger.error(`Offset out of range error: ${err}`); + console.error(`Offset out of range error: ${err}`); }); } + + +/** + * Produces modified messages to a specified Kafka topic. + * @param modifiedMessages An array of modified messages to be produced. + * @param topic The Kafka topic to which the messages will be produced. + * @returns A promise that resolves when the messages are successfully produced. + */ +async function produceModifiedMessages(modifiedMessages: any[], topic: any) { + try { + logger.info(`KAFKA :: PRODUCER :: a message sent to topic ${topic}`); + logger.debug(`KAFKA :: PRODUCER :: message ${getFormattedStringForDebug(modifiedMessages)}`); + return new Promise((resolve, reject) => { + const payloads = [ + { + topic: topic, + messages: JSON.stringify(modifiedMessages), // Convert modified messages to JSON string + }, + ]; + + // Send payloads to the Kafka producer + producer.send(payloads, (err) => { + if (err) { + logger.info('KAFKA :: PRODUCER :: Some Error Occurred '); + logger.error(`KAFKA :: PRODUCER :: Error : ${JSON.stringify(err)}`); + // reject(err); // Reject promise if there's an error + } else { + logger.info('KAFKA :: PRODUCER :: message sent successfully '); + // resolve(); // Resolve promise if messages are successfully produced + } + }); + }); + } catch (error) { + logger.error(`KAFKA :: PRODUCER :: Exception caught: ${JSON.stringify(error)}`); + throwError("COMMON", 400, "KAKFA_ERROR", "Some error occured in kafka"); // Re-throw the error after logging it + } +} + +export { produceModifiedMessages } // Export the produceModifiedMessages function for external use diff --git a/health-services/project-factory/src/server/kafka/Producer.ts b/health-services/project-factory/src/server/kafka/Producer.ts index cafa0ac6f66..b728b48a2ca 100644 --- a/health-services/project-factory/src/server/kafka/Producer.ts +++ b/health-services/project-factory/src/server/kafka/Producer.ts @@ -1,112 +1,25 @@ -import { Producer, KafkaClient } from 'kafka-node'; -import { getFormattedStringForDebug, logger } from "../utils/logger"; -import { shutdownGracefully, throwError } from '../utils/genericUtils'; -import config from '../config'; - -let kafkaClient: KafkaClient; -let producer: Producer; - -const createKafkaClientAndProducer = () => { - kafkaClient = new KafkaClient({ - kafkaHost: config?.host?.KAFKA_BROKER_HOST, - connectRetryOptions: { retries: 1 }, - }); - - // Event listener for 'error' event, indicating that the client encountered an error - kafkaClient.on('error', (err: any) => { - logger.error('Kafka client is in error state'); // Log message indicating client is in error state - console.error(err.stack || err); // Log the error stack or message - shutdownGracefully(); - }); - - producer = new Producer(kafkaClient, { partitionerType: 2 }); - - producer.on('ready', () => { - logger.info('Producer is ready'); - checkBrokerAvailability(); - }); - - producer.on('error', (err: any) => { - logger.error('Producer is in error state'); - console.error(err); - shutdownGracefully(); - }); -}; - -// Function to check broker availability by listing all brokers -const checkBrokerAvailability = () => { - kafkaClient.loadMetadataForTopics([], (err: any, data: any) => { - if (err) { - logger.error('Error checking broker availability:', err); - shutdownGracefully(); - } else { - const brokers = data[1]?.metadata || {}; - const brokerCount = Object.keys(brokers).length; - logger.info('Broker count:' + String(brokerCount)); - - if (brokerCount <= 0) { - logger.error('No brokers found. Shutting down the service.'); - shutdownGracefully(); - } else { - logger.info('Brokers are available:', brokers); - } - } - }); -}; - - -createKafkaClientAndProducer(); - -const sendWithReconnect = (payloads: any[]): Promise => { - return new Promise((resolve, reject) => { - // Send the message initially - producer.send(payloads, async (err: any) => { - if (err) { - logger.error('Error sending message:', err); - logger.debug(`Was trying to send: ${getFormattedStringForDebug(payloads)}`); - - // Attempt to reconnect and retry - logger.error('Reconnecting producer and retrying...'); - producer.close(() => { - createKafkaClientAndProducer(); - setTimeout(() => { - // Retry sending after reconnection - producer.send(payloads, (err: any) => { - if (err) { - logger.error('Failed to send message after reconnection:', err); - return reject(err); // Final failure, reject promise - } else { - logger.info('Message sent successfully after reconnection'); - resolve(); - } - }); - }, 2000); // wait before retrying after reconnect - }); - } else { - logger.info('Message sent successfully'); - resolve(); - } - }); - }); -}; - - -async function produceModifiedMessages(modifiedMessages: any[], topic: any) { - try { - logger.info(`KAFKA :: PRODUCER :: A message sent to topic ${topic}`); - logger.debug(`KAFKA :: PRODUCER :: Message ${JSON.stringify(modifiedMessages)}`); - const payloads = [ - { - topic: topic, - messages: JSON.stringify(modifiedMessages), - }, - ]; - - await sendWithReconnect(payloads); - } catch (error) { - logger.error(`KAFKA :: PRODUCER :: Exception caught: ${JSON.stringify(error)}`); - throwError("COMMON", 400, "KAFKA_ERROR", "Some error occurred in Kafka"); // Re-throw the error after logging it - } -} - -export { produceModifiedMessages }; +import config from '../config'; // Importing configuration settings +import { Producer, KafkaClient } from 'kafka-node'; // Importing Producer and KafkaClient from 'kafka-node' library +import { logger } from "../utils/logger"; + +// Creating a new Kafka client instance using the configured Kafka broker host +const kafkaClient = new KafkaClient({ + kafkaHost: config?.host?.KAFKA_BROKER_HOST, // Configuring Kafka broker host + connectRetryOptions: { retries: 1 }, // Configuring connection retry options +}); + +// Creating a new Kafka producer instance using the Kafka client +const producer = new Producer(kafkaClient, { partitionerType: 2 }); // Using partitioner type 2 + +// Event listener for 'ready' event, indicating that the producer is ready to send messages +producer.on('ready', () => { + logger.info('Producer is ready'); // Log message indicating producer is ready +}); + +// Event listener for 'error' event, indicating that the producer encountered an error +producer.on('error', (err) => { + logger.error('Producer is in error state'); // Log message indicating producer is in error state + console.error(err.stack || err); // Log the error stack or message +}); + +export { producer }; // Exporting the producer instance for external use diff --git a/health-services/project-factory/src/server/models/Boundary.d.ts b/health-services/project-factory/src/server/models/Boundary.d.ts deleted file mode 100644 index 576ef939992..00000000000 --- a/health-services/project-factory/src/server/models/Boundary.d.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { AuditDetails } from "./MDMS"; - -/** - * Represents the response structure for a boundary entity search. - */ -export interface BoundaryEntityResponse { - /** Array of boundary entities returned in the response */ - Boundary: BoundaryEntity[]; -} - -/** - * Represents a boundary entity within the MDMS system. - */ -interface BoundaryEntity { - /** Unique identifier for the boundary entity */ - id: string; - /** Tenant ID associated with the boundary entity */ - tenantId: string; - /** Unique code representing the boundary entity */ - code: string; - /** Geographical data for the boundary entity */ - geometry: any; - /** Audit information such as created/modified timestamps and users */ - auditDetails: AuditDetails; - /** Additional details related to the boundary entity */ - additionalDetails: any; -} - -/** - * Represents the response structure for a boundary hierarchy definition search. - */ -export interface BoundaryHierarchyDefinitionResponse { - /** Array of boundary hierarchy definitions in the response */ - BoundaryHierarchy: BoundaryHierarchy[]; -} - -/** - * Defines a boundary hierarchy within the MDMS system. - */ -interface BoundaryHierarchy { - /** Unique identifier for the hierarchy */ - id: string; - /** Tenant ID associated with the hierarchy */ - tenantId: string; - /** Type of hierarchy (e.g., administrative, geographic) */ - hierarchyType: string; - /** Elements representing each level within the hierarchy */ - boundaryHierarchy: BoundaryHierarchyElement[]; - /** Audit information such as created/modified timestamps and users */ - auditDetails: AuditDetails; -} - -/** - * Represents an element in the boundary hierarchy. - */ -interface BoundaryHierarchyElement { - /** Type of boundary at this level of the hierarchy */ - boundaryType: string; - /** Type of the parent boundary, if applicable */ - parentBoundaryType: null | string; - /** Indicates if the boundary is active */ - active: boolean; -} - -/** - * Represents the response structure for a boundary hierarchy relationship search. - */ -export interface BoundaryHierarchyRelationshipResponse { - /** Array of tenant boundaries returned in the response */ - TenantBoundary: TenantBoundary[]; -} - -/** - * Represents a tenant boundary structure within the MDMS system. - */ -interface TenantBoundary { - /** Tenant ID associated with this boundary */ - tenantId: string; - /** Type of hierarchy within which the boundary is categorized */ - hierarchyType: string; - /** Array of boundaries within this tenant's hierarchy */ - boundary: Boundary[]; -} - -/** - * Represents an individual boundary within a hierarchy, which may contain nested child boundaries. - */ -interface Boundary { - /** Unique identifier for the boundary */ - id: string; - /** Code representing the boundary */ - code: string; - /** Type of boundary (e.g., city, region) */ - boundaryType: string; - /** Array of child boundaries, allowing nested hierarchies */ - children: Boundary[]; -} - -/** - * Represents the search criteria for querying boundary hierarchy definitions. - */ -export interface BoundaryHierarchyDefinitionSearchCriteria { - /** Contains criteria for boundary type hierarchy search */ - BoundaryTypeHierarchySearchCriteria: BoundaryTypeHierarchySearchCriteria; -} - -/** - * Defines the criteria for searching a specific boundary type hierarchy. - */ -interface BoundaryTypeHierarchySearchCriteria { - /** Tenant ID for filtering the search results */ - tenantId: string; - /** Type of hierarchy being queried (e.g., administrative levels) */ - hierarchyType: string; -} diff --git a/health-services/project-factory/src/server/models/MDMS.d.ts b/health-services/project-factory/src/server/models/MDMS.d.ts deleted file mode 100644 index 0a163e14f1c..00000000000 --- a/health-services/project-factory/src/server/models/MDMS.d.ts +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Criteria for MDMS v1 request - */ -interface MDMSv1Criteria { - tenantId: string; // Unique identifier for the tenant - moduleDetails: ModuleDetail[]; // Array of module details to fetch -} - -/** - * Represents details of a specific module in MDMS v1 - */ -interface ModuleDetail { - moduleName: string; // Name of the module - masterDetails: MasterDetail[]; // Array of master data details for this module -} - -/** - * Details of a specific master entity in a module - */ -interface MasterDetail { - name: string; // Name of the master entity - filter?: string; // Optional filter criteria for fetching specific master data -} - -/** - * Criteria for MDMS v2 request - */ -interface MDMSv2Criteria { - tenantId: string; // Unique identifier for the tenant - schemaCode: string; // Code representing the schema to query - ids?: string[]; // Optional array of specific IDs to fetch - uniqueIdentifiers?: string[]; // Optional array of unique identifiers for the data -} - -/** - * Response structure for MDMS v1 response - */ -export interface MDMSv1Response { - MdmsRes: any; // Response payload, structure may vary -} - -/** - * Response structure for MDMS v2 response - */ -export interface MDMSv2Response { - mdms: MDMS[]; // Array of MDMS records -} - -/** - * Represents a single MDMS record in v2 response - */ -interface MDMS { - id: string; // Unique identifier for the MDMS record - tenantId: string; // Tenant identifier for the record - schemaCode: string; // Schema code associated with this record - uniqueIdentifier: string; // Unique identifier within this schema - data: any; // Data payload for the record - isActive: boolean; // Indicates if the record is active - auditDetails: AuditDetails; // Audit details for tracking changes -} - -/** - * Audit details containing metadata about record creation and modification - */ -interface AuditDetails { - createdBy: string; // ID of the user who created the record - lastModifiedBy: string; // ID of the user who last modified the record - createdTime: number; // Timestamp when the record was created - lastModifiedTime: number; // Timestamp when the record was last modified -} - -/** - * Response structure for MDMS schema definitions - */ -export interface MDMSSchemaResponse { - SchemaDefinitions: SchemaDefinition[]; // Array of schema definitions -} - -/** - * Represents a single schema definition in the MDMS response - */ -interface SchemaDefinition { - id: string; // Unique identifier for the schema definition - tenantId: string; // Tenant identifier associated with this schema - code: string; // Code identifying the schema - description: null | string; // Description of the schema, if available - definition: Definition; // Schema structure definition - isActive: boolean; // Indicates if the schema is active - auditDetails: AuditDetails; // Audit metadata for the schema definition -} - -/** - * Detailed structure of a schema definition - */ -interface Definition { - type: string; // Type of schema (e.g., object, array) - title?: string; // Optional title of the schema - $schema: string; // URI of the schema - required: string[]; // Array of required fields - "x-unique": string[]; // Array of unique constraints - properties?: any; // Properties within the schema - "x-ref-schema"?: XRefSchema[]; // Array of cross-references to other schemas - description?: string; // Optional description of the schema - additionalProperties?: boolean; // Indicates if additional properties are allowed - unique?: string[]; // Array of fields that must be unique -} - -/** - * Cross-reference schema for related fields - */ -interface XRefSchema { - fieldPath: string; // Path to the field within the schema - schemaCode: string; // Code of the schema that is referenced -} - -/** - * Criteria for requesting MDMS schema definitions - */ -export interface MDMSSchemaRequestCriteria { - SchemaDefCriteria: SchemaDefCriteria; // Criteria details for schema definition request -} - -/** - * Detailed criteria structure for schema definition requests - */ -interface SchemaDefCriteria { - tenantId: string; // Tenant identifier for the schema definition - limit: number; // Limit on the number of schema definitions to fetch - codes?: string[]; // Optional array of schema codes to retrieve -} - -/** - * Criteria for requesting MDMS schema definitions - */ -export interface MDMSv1RequestCriteria { - MdmsCriteria: MDMSv1Criteria; // Criteria details for schema definition request -} - -/** - * Criteria for requesting MDMS schema definitions - */ -export interface MDMSv2RequestCriteria { - MdmsCriteria: MDMSv2Criteria; // Criteria details for schema definition request -} diff --git a/health-services/project-factory/src/server/models/index.ts b/health-services/project-factory/src/server/models/index.ts deleted file mode 100644 index bd0e5462792..00000000000 --- a/health-services/project-factory/src/server/models/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as MDMSModels from './MDMS'; -import * as BoundaryModels from './Boundary'; - - -export { - MDMSModels, - BoundaryModels -}; diff --git a/health-services/project-factory/src/server/service/campaignManageService.ts b/health-services/project-factory/src/server/service/campaignManageService.ts index bd9ce407221..3d3652bb441 100644 --- a/health-services/project-factory/src/server/service/campaignManageService.ts +++ b/health-services/project-factory/src/server/service/campaignManageService.ts @@ -1,17 +1,15 @@ import express from "express"; -import { processBasedOnAction, processFetchMicroPlan, searchProjectCampaignResourcData, updateCampaignAfterSearch } from "../utils/campaignUtils"; +import { processBasedOnAction, searchProjectCampaignResourcData } from "../utils/campaignUtils"; import { logger } from "../utils/logger"; -import { validateMicroplanRequest, validateProjectCampaignRequest, validateSearchProcessTracksRequest } from "../validators/campaignValidators"; +import { validateProjectCampaignRequest, validateSearchProjectCampaignRequest } from "../validators/campaignValidators"; import { validateCampaignRequest } from "../validators/genericValidator"; import { createRelatedResouce } from "../api/genericApis"; import { enrichCampaign } from "../api/campaignApis"; -import { getProcessDetails, modifyProcessDetails } from "../utils/processTrackUtils"; async function createProjectTypeCampaignService(request: express.Request) { // Validate the request for creating a project type campaign - logger.info("VALIDATING:: for project type"); await validateProjectCampaignRequest(request, "create"); - logger.info("VALIDATED:: THE PROJECT TYPE CREATE REQUEST"); + logger.info("VALIDATED THE PROJECT TYPE CREATE REQUEST"); // Process the action based on the request type await processBasedOnAction(request, "create"); @@ -28,14 +26,16 @@ async function updateProjectTypeCampaignService(request: express.Request) { return request?.body?.CampaignDetails; } -async function searchProjectTypeCampaignService(campaignDetails: any +async function searchProjectTypeCampaignService( + request: express.Request, ) { - // await validateSearchProjectCampaignRequest(request); + // Validate the search request for project type campaigns + await validateSearchProjectCampaignRequest(request); logger.info("VALIDATED THE PROJECT TYPE SEARCH REQUEST"); // Search for project campaign resource data - const { responseData, totalCount } = await searchProjectCampaignResourcData(campaignDetails); - const responseBody: any = { CampaignDetails: responseData, totalCount: totalCount } + await searchProjectCampaignResourcData(request); + const responseBody: any = { CampaignDetails: request?.body?.CampaignDetails, totalCount: request?.body?.totalCount } return responseBody; }; @@ -53,47 +53,10 @@ async function createCampaignService( return requestBody?.Campaign }; -async function searchProcessTracksService( - request: express.Request -) { - await validateSearchProcessTracksRequest(request) - logger.info("VALIDATED THE PROCESS SEARCH REQUEST"); - - // Search and return related process tracks - const processDetailsArray = await getProcessDetails(request?.query?.campaignId as string) - - // sort and modify process details so that details with status as toBeCompleted comes in last - const resultArray = modifyProcessDetails(processDetailsArray) - - return resultArray -}; - -async function retryProjectTypeCampaignService(request: express.Request) { - logger.info("RETRYING THE PROJECT TYPE CAMPAIGN"); - await validateProjectCampaignRequest(request, "retry"); - logger.info("VALIDATED THE PROJECT TYPE RETRY REQUEST"); - request.body.CampaignDetails.action = "draft"; - await processBasedOnAction(request, "update"); - return request?.body?.CampaignDetails; -} - -async function fetchFromMicroplanService(request: express.Request) { - logger.info("FETCHING DATA FROM MICROPLAN"); - await validateMicroplanRequest(request); - logger.info("UPDATE CAMPAIGN OBJECT") - await updateCampaignAfterSearch(request, "MICROPLAN_FETCHING") - logger.info("Validated request successfully"); - processFetchMicroPlan(request); - return request.body.CampaignDetails; -} - export { createProjectTypeCampaignService, updateProjectTypeCampaignService, searchProjectTypeCampaignService, - createCampaignService, - searchProcessTracksService, - retryProjectTypeCampaignService, - fetchFromMicroplanService -} + createCampaignService +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/service/dataManageService.ts b/health-services/project-factory/src/server/service/dataManageService.ts index bf1f17b8355..ed224dc824f 100644 --- a/health-services/project-factory/src/server/service/dataManageService.ts +++ b/health-services/project-factory/src/server/service/dataManageService.ts @@ -1,19 +1,14 @@ import express from "express"; import { processGenericRequest } from "../api/campaignApis"; import { createAndUploadFile, getBoundarySheetData } from "../api/genericApis"; -import { getLocalizedName, getResourceDetails, processDataSearchRequest } from "../utils/campaignUtils"; -import { addDataToSheet, enrichResourceDetails, getLocalizedMessagesHandler, searchGeneratedResources, processGenerate, replicateRequest } from "../utils/genericUtils"; -import { getFormattedStringForDebug, logger } from "../utils/logger"; +import { getLocalizedName, processDataSearchRequest } from "../utils/campaignUtils"; +import { addDataToSheet, enrichResourceDetails, getLocalizedMessagesHandler, searchGeneratedResources, processGenerate, throwError } from "../utils/genericUtils"; +import { logger } from "../utils/logger"; import { validateCreateRequest, validateDownloadRequest, validateSearchRequest } from "../validators/campaignValidators"; import { validateGenerateRequest } from "../validators/genericValidator"; import { getLocalisationModuleName } from "../utils/localisationUtils"; import { getBoundaryTabName } from "../utils/boundaryUtils"; import { getNewExcelWorkbook } from "../utils/excelUtils"; -import { redis, checkRedisConnection } from "../utils/redisUtils"; // Importing checkRedisConnection function -import config from '../config/index' -import { callGenerate } from "../utils/generateUtils"; -import { generatedResourceStatuses } from "../config/constants"; - const generateDataService = async (request: express.Request) => { @@ -33,89 +28,34 @@ const downloadDataService = async (request: express.Request) => { const type = request.query.type; // Get response data from the database const responseData = await searchGeneratedResources(request); - const resourceDetails = await getResourceDetails(request); - // Check if response data is available - if ( - !responseData || - (responseData.length === 0 && !request?.query?.id) || - responseData?.[0]?.status === generatedResourceStatuses.failed - ) { - logger.error(`No data of type '${type}' with status 'Completed' or the provided ID is present in the database.`) + if (!responseData || responseData.length === 0 && !request?.query?.id) { + logger.error("No data of type " + type + " with status Completed or with given id presnt in db ") // Throw error if data is not found - const newRequestBody = { - RequestInfo: request?.body?.RequestInfo - }; - const params = { - type: request?.query?.type, - tenantId: request?.query?.tenantId, - forceUpdate: 'true', - hierarchyType: request?.query?.hierarchyType, - campaignId: request?.query?.campaignId, - }; - const newRequestToGenerate = replicateRequest(request, newRequestBody, params); - // Added auto generate since no previous generate request found - logger.info(`Triggering auto generate since no resources got generated for the given Campaign Id ${request?.query?.campaignId} & type ${request?.query?.type} `) - callGenerate(newRequestToGenerate, request?.query?.type); - - // throwError("CAMPAIGN", 500, "GENERATION_REQUIRE"); - } - - // Send response with resource details - if (resourceDetails != null && responseData != null && responseData.length > 0) { - responseData[0].additionalDetails = { - ...(responseData[0].additionalDetails || {}), - ...(resourceDetails?.additionalDetails || {}) - }; + throwError("CAMPAIGN", 500, "GENERATION_REQUIRE"); } - - return responseData; } const getBoundaryDataService = async ( - request: express.Request, enableCaching = false) => { + request: express.Request) => { try { - const { hierarchyType, campaignId } = request?.query; - const cacheTTL = config?.cacheTime; // TTL in seconds (5 minutes) - const cacheKey = `${campaignId}-${hierarchyType}`; - let isRedisConnected = false; - let cachedData: any = null; - if (cacheKey && enableCaching) { - isRedisConnected = await checkRedisConnection(); - cachedData = await redis.get(cacheKey); // Get cached data - } - if (cachedData) { - logger.info("CACHE HIT :: " + cacheKey); - logger.debug(`CACHED DATA :: ${getFormattedStringForDebug(cachedData)}`); - - // Reset the TTL for the cache key - if (config.cacheValues.resetCache) { - await redis.expire(cacheKey, cacheTTL); - } - - return JSON.parse(cachedData); // Return parsed cached data if available - } else { - logger.info("NO CACHE FOUND :: REQUEST :: " + cacheKey); - } const workbook = getNewExcelWorkbook(); - const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType), true); + const { hierarchyType } = request?.query; + const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); - const localizationMap = { ...(localizationMapHierarchy || {}), ...localizationMapModule }; + const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; // Retrieve boundary sheet data const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - addDataToSheet(request, boundarySheet, boundarySheetData, '93C47D', 40, true); - const boundaryFileDetails: any = await createAndUploadFile(workbook, request); + addDataToSheet(boundarySheet, boundarySheetData); + const BoundaryFileDetails: any = await createAndUploadFile(workbook, request); // Return boundary file details logger.info("RETURNS THE BOUNDARY RESPONSE"); - if (cacheKey && isRedisConnected) { - await redis.set(cacheKey, JSON.stringify(boundaryFileDetails), "EX", cacheTTL); // Cache the response data with TTL - } - return boundaryFileDetails; + return BoundaryFileDetails; } catch (e: any) { - console.log(e) logger.error(String(e)) // Handle errors and send error response throw (e); @@ -125,10 +65,7 @@ const getBoundaryDataService = async ( const createDataService = async (request: any) => { - const hierarchyType = request?.body?.ResourceDetails?.hierarchyType; - const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId, getLocalisationModuleName(hierarchyType), true); - const localizationMapModule = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); - const localizationMap = { ...(localizationMapHierarchy || {}), ...localizationMapModule }; + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); // Validate the create request logger.info("Validating data create request") await validateCreateRequest(request, localizationMap); @@ -158,4 +95,4 @@ export { getBoundaryDataService, createDataService, searchDataService -} +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts b/health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts deleted file mode 100644 index 568657d168d..00000000000 --- a/health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts +++ /dev/null @@ -1,44 +0,0 @@ -import config from "../config/index"; -import { httpRequest } from "./request"; -import { processBoundary } from "./campaignUtils"; - -async function consolidateBoundaries(messageObject: any, hierarchyType: any, tenantId: any, code: any, boundaries: any) { - const params = { - tenantId: tenantId, - codes: code, - hierarchyType: hierarchyType, - includeChildren: true, - }; - const header = { - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId - }${params.codes || ""}${params?.includeChildren || ""}`, - }; - const boundaryResponse = await httpRequest( - config.host.boundaryHost + config.paths.boundaryRelationship, - messageObject?.RequestInfo, - params, - undefined, - undefined, - header - ); - if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { - const boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { - acc[boundary.code] = boundary?.includeAllChildren; - return acc; - }, {}); - const boundaryCodes = new Set( - boundaries.map((boundary: any) => boundary.code) - ); - await processBoundary( - boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], - boundaries, - boundaryChildren[ - boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]?.code - ], - boundaryCodes, - boundaryChildren - ); - return boundaries; - } -} -export { consolidateBoundaries, } \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/boundaryUtils.ts b/health-services/project-factory/src/server/utils/boundaryUtils.ts index 9b6e0396d19..40aa4f437ed 100644 --- a/health-services/project-factory/src/server/utils/boundaryUtils.ts +++ b/health-services/project-factory/src/server/utils/boundaryUtils.ts @@ -1,6 +1,4 @@ import config from "../config/index"; -import { logger } from "./logger"; -import { httpRequest } from "./request"; @@ -15,54 +13,3 @@ export const getBoundaryTabName = () => { return config?.boundary?.boundaryTab; }; - -export async function getLatLongMapForBoundaryCodes(request:any, boundaryCodeList: any[]) { - const chunkSize = 20; - const boundaryCodeChunks = []; - let boundaryCodeLatLongMap: { [key: string]: number[] } = {}; // Map to hold lat/long data for boundary codes - - // Split the boundaryCodeList into chunks of 20 - for (let i = 0; i < boundaryCodeList.length; i += chunkSize) { - boundaryCodeChunks.push(boundaryCodeList.slice(i, i + chunkSize)); - } - - // Process each chunk - for (const chunk of boundaryCodeChunks) { - const boundaryCodeString = chunk.join(", "); - - // Only proceed if there are valid boundary codes - if (boundaryCodeList.length > 0 && boundaryCodeString) { - logger.info(`Creating boundary entities for codes: ${boundaryCodeString}`); - - try { - // Make the API request to fetch boundary entities - const boundaryEntityResponse = await httpRequest( - config.host.boundaryHost + config.paths.boundaryEntity, - request.body, // Passing the request body - { tenantId: request?.query?.tenantId, codes: boundaryCodeString } // Query params - ); - - // Process the boundary entities and extract lat/long for 'Point' geometries - if (boundaryEntityResponse?.Boundary) { - for (const boundary of boundaryEntityResponse.Boundary) { - if (boundary?.geometry && boundary.geometry.type === "Point") { - boundaryCodeLatLongMap[boundary.code] = boundary.geometry.coordinates; - } - } - } - - } catch (error: any) { - // Log error but do not stop the process for other chunks - console.log(error); - logger.error(`Failed to fetch boundary entities for codes: ${boundaryCodeString}, Error: ${error.message}`); - } - - } else { - // Log when the chunk is empty or invalid - logger.debug(`Skipping empty or invalid chunk: ${boundaryCodeString}`); - } - } - boundaryCodeLatLongMap['ADMIN_MO'] = [200,100]; - // Return or process the map further if needed - return boundaryCodeLatLongMap; -} diff --git a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts index a6f1b821c00..ac34761d2f8 100644 --- a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts @@ -1,19 +1,12 @@ import createAndSearch from "../config/createAndSearch"; import config from "../config"; -import { getDataFromSheet, getLocalizedMessagesHandlerViaRequestInfo, replicateRequest, throwError } from "./genericUtils"; +import { getDataFromSheet, throwError } from "./genericUtils"; import { getFormattedStringForDebug, logger } from "./logger"; -import { defaultheader, httpRequest } from "./request"; -import { produceModifiedMessages } from "../kafka/Producer"; -import { enrichAndPersistCampaignWithError, getLocalizedName } from "./campaignUtils"; +import { httpRequest } from "./request"; +import { produceModifiedMessages } from "../kafka/Listener"; +import { getLocalizedName } from "./campaignUtils"; import { campaignStatuses, resourceDataStatuses } from "../config/constants"; -import { createCampaignService, searchProjectTypeCampaignService } from "../service/campaignManageService"; -import { persistTrack } from "./processTrackUtils"; -import { processTrackTypes, processTrackStatuses } from "../config/constants"; -import { createProjectFacilityHelper, createProjectResourceHelper, createProjectStaffHelper } from "../api/genericApis"; -import { buildSearchCriteria, delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary, processResources } from "./onGoingCampaignUpdateUtils"; -import { searchDataService } from "../service/dataManageService"; -import { getHierarchy } from "../api/campaignApis"; -import { consolidateBoundaries } from "./boundariesConsolidationUtils"; +import { createCampaignService } from "../service/campaignManageService"; async function createBoundaryWithProjectMapping(projects: any, boundaryWithProject: any) { @@ -27,249 +20,54 @@ async function createBoundaryWithProjectMapping(projects: any, boundaryWithProje } } -export function getPvarIds(messageObject: any) { - //update to set now - logger.info("campaign product resource mapping started"); +function getPvarIds(messageObject: any) { const deliveryRules = messageObject?.CampaignDetails?.deliveryRules; const uniquePvarIds = new Set(); // Create a Set to store unique pvar IDs if (deliveryRules) { for (const deliveryRule of deliveryRules) { - const products = deliveryRule?.resources; + const products = deliveryRule?.products; if (products) { for (const product of products) { - uniquePvarIds.add(product?.productVariantId); // Add pvar ID to the Set + uniquePvarIds.add(product?.value); // Add pvar ID to the Set } } } } - logger.info(`campaign product resource found items : ${JSON.stringify(uniquePvarIds)}`); return Array.from(uniquePvarIds); // Convert Set to array before returning } -function trimBoundaryCodes(root: any) { - if (root) { - root.code = root.code.trim(); // Trim the code - - // Recursively trim the codes in the children - for (const child of root.children) { - trimBoundaryCodes(child); - } - } -} - -async function getAllBoundaries(messageObject: any, tenantId: any, rootBoundary: any, hierarchyType: any) { - const BoundarySearchBody = { - RequestInfo: messageObject?.RequestInfo, - } - const params = { - tenantId, - codes: rootBoundary, - hierarchyType, - includeChildren: true - } - const header = { - ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, - } - const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, BoundarySearchBody, params, undefined, undefined, header); - trimBoundaryCodes(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]); - return boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0] -} - -// Function to find the path to a given boundary code -function findPath(root: any, code: string, path: any[] = []) { - if (root.code === code) { - return [...path, root]; - } - for (const child of root.children) { - const result: any = findPath(child, code, [...path, root]); - if (result) return result; - } - return null; -} - -// Function to find the common parent for multiple codes -function findCommonParent(codes: string[], root: any) { - if (codes.length === 0) return null; - - // Find paths for all codes - const paths = codes.map(code => findPath(root, code)).filter(path => path !== null); - - if (paths.length === 0) return null; - - // Compare paths to find the common ancestor - let commonParent: any = null; - - for (let i = 0; i < Math.min(...paths.map(path => path.length)); i++) { - const currentParent = paths[0][i]; - if (paths.every(path => path[i] && path[i].code === currentParent.code)) { - commonParent = currentParent; - } else { - break; - } - } - - return commonParent?.code; -} - -function mapBoundaryCodes(resource: any, code: string, boundaryCode: string, boundaryCodes: any, allBoundaries: any) { - // Split boundary codes if they have comma separated values - const boundaryCodesArray = boundaryCode - ? boundaryCode.includes(',') - ? boundaryCode.split(',').map((bc: string) => bc.trim()).filter(Boolean) - : [boundaryCode.trim()] - : []; - if (resource?.type == "user" && boundaryCodesArray?.length > 1 && config.user.mapUserViaCommonParent) { - const commonParent = findCommonParent(boundaryCodesArray, allBoundaries); - if (commonParent) { - logger.info(`Boundary Codes Array ${boundaryCodesArray.join(",")} for resource ${resource?.type} has common parent ${commonParent}`) - if (!boundaryCodes[resource?.type]) { - boundaryCodes[resource?.type] = {}; - } - if (!boundaryCodes[resource?.type][commonParent]) { - boundaryCodes[resource?.type][commonParent] = []; - } - boundaryCodes[resource?.type][commonParent].push(code); - logger.info(`Common Parent Boundary code ${commonParent} mapped to resource ${resource?.type} with code ${code}`) - } - } - else { - boundaryCodesArray.forEach((trimmedBC: string) => { - // Trim any leading or trailing spaces - if (!boundaryCodes[resource?.type]) { - boundaryCodes[resource?.type] = {}; - } - if (!boundaryCodes[resource?.type][trimmedBC]) { - boundaryCodes[resource?.type][trimmedBC] = []; - } - boundaryCodes[resource?.type][trimmedBC].push(code); - logger.info(`Boundary code ${trimmedBC} mapped to resource ${resource?.type} with code ${code}`) - }); - } -} - - -function splitBoundaryCodes(boundaryCode: string) { - return boundaryCode.includes(',') - ? boundaryCode.split(',').map((code: string) => code.trim()).filter(Boolean) - : [boundaryCode.trim()].filter(Boolean); -} - - -async function fetchActiveIdentifiersFromParentCampaign( - resource: any, - resourcesFromParentCampaign: any[], - messageObject: any, - sheetName: any, - localizationMap: any, - activeColumn: string, - uniqueCodeColumn: string -): Promise { - let activeUniqueIdentifiersFromParent: any[] = []; - - if (messageObject?.parentCampaign) { - const matchingParentResource = resourcesFromParentCampaign.find( - (parentResource: any) => parentResource.type === resource.type - ); - - if (matchingParentResource) { - const parentCreateResourceId = matchingParentResource.createResourceId || ''; - const searchCriteria = buildSearchCriteria(messageObject, [parentCreateResourceId], matchingParentResource?.type); - const responseFromDataSearch = await searchDataService(replicateRequest(messageObject, searchCriteria)); - - const parentProcessedFileStoreId = responseFromDataSearch?.[0]?.processedFilestoreId; - - const parentResourceData: any = await getDataFromSheet( - messageObject, - parentProcessedFileStoreId, - messageObject?.Campaign?.tenantId, - undefined, - sheetName[matchingParentResource?.type], - localizationMap - ); - - activeUniqueIdentifiersFromParent = parentResourceData - .filter((row: any) => row[activeColumn] === "Active") - .map((row: any) => row[uniqueCodeColumn]); - } - } - - return activeUniqueIdentifiersFromParent; -} - - async function enrichBoundaryCodes(resources: any[], messageObject: any, boundaryCodes: any, sheetName: any) { const localizationMap: any = messageObject?.localizationMap - const allBoundaries = await getAllBoundaries(messageObject, messageObject?.Campaign?.tenantId, messageObject?.Campaign?.boundaryCode, messageObject?.Campaign?.hierarchyType); - const delinkOperations: any = []; - const linkOperations: any = []; - const resourcesFromParentCampaign = messageObject?.parentCampaign?.resources || []; for (const resource of resources) { - const uniqueCodeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.uniqueIdentifierColumnName, localizationMap) - let activeColumn: any; - if (createAndSearch?.[resource?.type]?.activeColumn && createAndSearch?.[resource?.type]?.activeColumnName) { - activeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.activeColumnName, localizationMap); - } const processedFilestoreId = resource?.processedFilestoreId; - const activeUniqueIdentifiersFromParent = await fetchActiveIdentifiersFromParentCampaign( - resource, - resourcesFromParentCampaign, - messageObject, - sheetName, - localizationMap, - activeColumn, - uniqueCodeColumn - ); if (processedFilestoreId) { const dataFromSheet: any = await getDataFromSheet(messageObject, processedFilestoreId, messageObject?.Campaign?.tenantId, undefined, sheetName[resource?.type], localizationMap); for (const data of dataFromSheet) { + const uniqueCodeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.uniqueIdentifierColumnName, localizationMap) const code = data[uniqueCodeColumn]; if (code) { // Extract boundary codes const boundaryCode = data[getLocalizedName(createAndSearch?.[resource?.type]?.boundaryValidation?.column, localizationMap)]; - let active: any = "Active"; + var active: any = "Active"; if (createAndSearch?.[resource?.type]?.activeColumn && createAndSearch?.[resource?.type]?.activeColumnName) { + var activeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.activeColumnName, localizationMap); active = data[activeColumn]; } - if (boundaryCode && active === "Active") { - if (!messageObject?.parentCampaign) { - mapBoundaryCodes(resource, code, boundaryCode, boundaryCodes, allBoundaries); - } - else { - const existingBoundaryColumn = splitBoundaryCodes( - data[getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", localizationMap)] || "" - ); - - const newBoundaryColumn = splitBoundaryCodes(boundaryCode); - - existingBoundaryColumn.forEach((boundary: any) => { - if (!newBoundaryColumn.includes(boundary)) { - delinkOperations.push({ - resource, messageObject, boundary, code, isDelink: true - }); - } - }); - - // Collect link operations for new boundaries - newBoundaryColumn.forEach((boundary: any) => { - linkOperations.push({ - resource, messageObject, boundary, code, isDelink: false - }); - }); - } - } - else { - if (messageObject?.parentCampaign) { - if (boundaryCode && activeUniqueIdentifiersFromParent.includes(code) && active !== "Active") { - const boundariesToBeDelinked = splitBoundaryCodes(data[getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", localizationMap)] || ""); - boundariesToBeDelinked.forEach((boundary: any) => { - delinkOperations.push({ - resource, messageObject, boundary, code, isDelink: true - }); - }); - + if (boundaryCode && active == "Active") { + // Split boundary codes if they have comma separated values + const boundaryCodesArray = boundaryCode.split(','); + boundaryCodesArray.forEach((bc: string) => { + // Trim any leading or trailing spaces + const trimmedBC = bc.trim(); + if (!boundaryCodes[resource?.type]) { + boundaryCodes[resource?.type] = {}; + } + if (!boundaryCodes[resource?.type][trimmedBC]) { + boundaryCodes[resource?.type][trimmedBC] = []; } - } + boundaryCodes[resource?.type][trimmedBC].push(code); + logger.info(`Boundary code ${trimmedBC} mapped to resource ${resource?.type} with code ${code}`) + }); } } else { @@ -278,41 +76,6 @@ async function enrichBoundaryCodes(resources: any[], messageObject: any, boundar } } } - - // Process delink operations sequentially - for (const delinkData of delinkOperations) { - try { - const isMappingAlreadyPresent = await delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary( - delinkData.resource, - delinkData.messageObject, - delinkData.boundary, - delinkData.code, - delinkData.isDelink - ); - logger.info(`Delinking ${delinkData.boundary} from ${delinkData.code} resource`); - logger.info("Delink operation complete, mapping present:", isMappingAlreadyPresent); - } catch (err: any) { - logger.error(`Error during delink operation for ${delinkData.boundary}: ${err.message}`); - } - } - - // Process link operations sequentially - for (const linkData of linkOperations) { - try { - const isMappingAlreadyPresent = await delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary( - linkData.resource, - linkData.messageObject, - linkData.boundary, - linkData.code, - linkData.isDelink - ); - if (!isMappingAlreadyPresent) { - mapBoundaryCodes(linkData.resource, linkData.code, linkData.boundary, boundaryCodes, allBoundaries); - } - } catch (err: any) { - logger.error(`Error during link operation for ${linkData.boundary}: ${err.message}`); - } - } } @@ -338,21 +101,6 @@ async function enrichBoundaryWithProject(messageObject: any, boundaryWithProject logger.debug(`boundaryWise Project mapping : ${getFormattedStringForDebug(boundaryWithProject)}`); logger.info("boundaryCodes mapping : " + JSON.stringify(boundaryCodes)); } -function filterBoundariesByHierarchy(hierarchy: any, boundaries: any) { - // Iterate through the hierarchy in order - for (const level of hierarchy) { - // Find boundaries matching the current level type - const matchingBoundaries = boundaries.filter((boundary: any) => boundary.type === level); - - if (matchingBoundaries.length > 0) { - // If matches are found, return them - return matchingBoundaries; - } - } - - // If no matches are found, return an empty array - return []; -} async function getProjectMappingBody(messageObject: any, boundaryWithProject: any, boundaryCodes: any) { const Campaign: any = { @@ -360,60 +108,16 @@ async function getProjectMappingBody(messageObject: any, boundaryWithProject: an tenantId: messageObject?.Campaign?.tenantId, CampaignDetails: [] } - const newlyAddedBoundaryCodes = new Set(); // A set to store unique boundary codes - if (messageObject?.CampaignDetails?.parentId) { - const CampaignDetails = { - "ids": [messageObject?.CampaignDetails?.id], - "tenantId": messageObject?.CampaignDetails?.tenantId - } - const campaignSearchResponse = await searchProjectTypeCampaignService(CampaignDetails); - const boundaries = campaignSearchResponse?.CampaignDetails?.[0]?.boundaries; - const hierarchy = await getHierarchy(messageObject, messageObject?.CampaignDetails?.tenantId, messageObject?.CampaignDetails?.hierarchyType); - const boundariesWhichAreRootInThisFlow = filterBoundariesByHierarchy(hierarchy, boundaries); - for (const boundary of boundariesWhichAreRootInThisFlow) { - const boundaryCodesFetchedFromGivenRoot = await consolidateBoundaries( - messageObject, - messageObject?.CampaignDetails?.hierarchyType, - messageObject?.CampaignDetails?.tenantId, - boundary?.code, - boundaries - ); - // Add each boundary code to the set if it exists - if (boundaryCodesFetchedFromGivenRoot && - Array.isArray(boundaryCodesFetchedFromGivenRoot) && - boundaryCodesFetchedFromGivenRoot.length > 0) { - boundaryCodesFetchedFromGivenRoot - .filter((boundary: any) => boundary?.code) // Filter boundaries with valid codes - .forEach((boundary: any) => newlyAddedBoundaryCodes.add(boundary.code)); - } - } - } - - for (const key of Object.keys(boundaryWithProject)) { if (boundaryWithProject[key]) { const resources: any[] = []; - if (messageObject?.CampaignDetails?.parentId && newlyAddedBoundaryCodes.has(key)) { - logger.info("project resource mapping for newly created projects in update flow") - const pvarIds = getPvarIds(messageObject); - if (pvarIds && Array.isArray(pvarIds) && pvarIds.length > 0) { - resources.push({ - type: "resource", - resourceIds: pvarIds - }) - } - } - - if (!messageObject?.CampaignDetails?.parentId) { - const pvarIds = getPvarIds(messageObject); - if (pvarIds && Array.isArray(pvarIds) && pvarIds.length > 0) { - resources.push({ - type: "resource", - resourceIds: pvarIds - }) - } + const pvarIds = getPvarIds(messageObject); + if (pvarIds && Array.isArray(pvarIds) && pvarIds.length > 0) { + resources.push({ + type: "resource", + resourceIds: pvarIds + }) } - for (const type of Object.keys(boundaryCodes)) { if (boundaryCodes[type][key] && Array.isArray(boundaryCodes[type][key]) && boundaryCodes[type][key].length > 0) { resources.push({ @@ -425,45 +129,39 @@ async function getProjectMappingBody(messageObject: any, boundaryWithProject: an Campaign.CampaignDetails.push({ projectId: boundaryWithProject[key], resources: resources - }); + }) } } return { RequestInfo: messageObject?.RequestInfo, - Campaign: Campaign, - CampaignDetails: messageObject?.CampaignDetails, - parentCampaign: messageObject?.parentCampaign + Campaign: Campaign } } async function fetchAndMap(resources: any[], messageObject: any) { - await persistTrack(messageObject?.Campaign?.id, processTrackTypes.prepareResourceForMapping, processTrackStatuses.inprogress) - const localizationMap = await getLocalizedMessagesHandlerViaRequestInfo(messageObject?.RequestInfo, messageObject?.Campaign?.tenantId); - messageObject.localizationMap = localizationMap - try { - const localizationMap = messageObject?.localizationMap; - const sheetName: any = { - "user": getLocalizedName(createAndSearch?.user?.parseArrayConfig?.sheetName, localizationMap), - "facility": getLocalizedName(createAndSearch?.facility?.parseArrayConfig?.sheetName, localizationMap) - } - // Object to store boundary codes - const boundaryCodes: any = {}; + const localizationMap = messageObject?.localizationMap; + const sheetName: any = { + "user": getLocalizedName(createAndSearch?.user?.parseArrayConfig?.sheetName, localizationMap), + "facility": getLocalizedName(createAndSearch?.facility?.parseArrayConfig?.sheetName, localizationMap) + } + // Object to store boundary codes + const boundaryCodes: any = {}; - await enrichBoundaryCodes(resources, messageObject, boundaryCodes, sheetName); - logger.info("boundaryCodes : " + JSON.stringify(boundaryCodes)); - var boundaryWithProject: any = {}; - await enrichBoundaryWithProject(messageObject, boundaryWithProject, boundaryCodes); - logger.info("boundaryWithProject : " + JSON.stringify(boundaryWithProject)); - var projectMappingBody = await getProjectMappingBody(messageObject, boundaryWithProject, boundaryCodes); - logger.info("projectMappingBody : " + JSON.stringify(projectMappingBody)); - logger.info("projectMapping started "); - } catch (error: any) { - console.log(error) - await persistTrack(messageObject?.Campaign?.id, processTrackTypes.prepareResourceForMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); - throw new Error(error) + await enrichBoundaryCodes(resources, messageObject, boundaryCodes, sheetName); + logger.info("boundaryCodes : " + JSON.stringify(boundaryCodes)); + var boundaryWithProject: any = {}; + await enrichBoundaryWithProject(messageObject, boundaryWithProject, boundaryCodes); + logger.info("boundaryWithProject : " + JSON.stringify(boundaryWithProject)); + const projectMappingBody = await getProjectMappingBody(messageObject, boundaryWithProject, boundaryCodes); + logger.info("projectMappingBody : " + JSON.stringify(projectMappingBody)); + logger.info("projectMapping started "); + const projectMappingResponse: any = await createCampaignService(projectMappingBody); + logger.info("Project Mapping Response received"); + if (projectMappingResponse) { + logger.info("Campaign Mapping done") + messageObject.CampaignDetails.status = campaignStatuses.inprogress + produceModifiedMessages(messageObject, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC) } - await persistTrack(messageObject?.Campaign?.id, processTrackTypes.prepareResourceForMapping, processTrackStatuses.completed) - await createCampaignService(projectMappingBody); } async function searchResourceDetailsById(resourceDetailId: string, messageObject: any) { @@ -504,197 +202,42 @@ async function processCampaignMapping(messageObject: any) { logger.info("Campaign Already In Progress and Mapped"); } else { - await persistTrack(id, processTrackTypes.confirmingResourceCreation, processTrackStatuses.inprogress); - try { - var completedResources: any = [] - var resources = []; - for (const resourceDetailId of resourceDetailsIds) { - var retry = 75; - while (retry--) { - const response = await searchResourceDetailsById(resourceDetailId, messageObject); - logger.info(`response for resourceDetailId: ${resourceDetailId}`); - logger.debug(` response : ${getFormattedStringForDebug(response)}`) - if (response?.status == "invalid") { - logger.error(`resource type ${response?.type} is invalid`); - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Data File for resource type " + response?.type + " is invalid"); - break; - } - else if (response?.status == resourceDataStatuses.failed) { - logger.error(`resource type ${response?.type} is ${resourceDataStatuses.failed}`); - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", `Resource creation of type ${response?.type} failed : with errorlog ${response?.additionalDetails?.error}`); - break; - } - else if (response?.status == resourceDataStatuses.completed) { - completedResources.push(resourceDetailId); - resources.push(response); - break; - } - else { - logger.info(`Waiting for 20 seconds for resource with id ${resourceDetailId} on retry ${retry}`); - await new Promise(resolve => setTimeout(resolve, 20000)); - } + var completedResources: any = [] + var resources = []; + for (const resourceDetailId of resourceDetailsIds) { + var retry = 75; + while (retry--) { + const response = await searchResourceDetailsById(resourceDetailId, messageObject); + logger.info(`response for resourceDetailId: ${resourceDetailId}`); + logger.debug(` response : ${getFormattedStringForDebug(response)}`) + if (response?.status == "invalid") { + logger.error(`resource with id ${resourceDetailId} is invalid`); + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + resourceDetailId + " is invalid"); + break; + } + else if (response?.status == resourceDataStatuses.failed) { + logger.error(`resource with id ${resourceDetailId} is ${resourceDataStatuses.failed}`); + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", `resource with id ${resourceDetailId} is ${resourceDataStatuses.failed} : with errorlog ${response?.additionalDetails?.error}`); + break; + } + else if (response?.status == resourceDataStatuses.completed) { + completedResources.push(resourceDetailId); + resources.push(response); + break; + } + else { + logger.info(`Waiting for 20 seconds for resource with id ${resourceDetailId} on retry ${retry}`); + await new Promise(resolve => setTimeout(resolve, 20000)); } - } - var uncompletedResourceIds = resourceDetailsIds?.filter((x: any) => !completedResources.includes(x)); - logger.info("uncompletedResourceIds " + JSON.stringify(uncompletedResourceIds)); - logger.info("completedResources " + JSON.stringify(completedResources)); - if (uncompletedResourceIds?.length > 0) { - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + JSON.stringify(uncompletedResourceIds) + " is not completed after long wait. Check file"); - } - } catch (error: any) { - console.log(error) - await persistTrack(id, processTrackTypes.confirmingResourceCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); - throw new Error(error) - } - await persistTrack(id, processTrackTypes.confirmingResourceCreation, processTrackStatuses.completed); - await fetchAndMap(resources, messageObject); - } -} - -export async function handleCampaignMapping(messageObject: any) { - try { - logger.info("Received a message for campaign mapping"); - logger.debug("Message Object of campaign mapping: " + getFormattedStringForDebug(messageObject)); - await processCampaignMapping(messageObject); - } catch (error) { - logger.error("Error in campaign mapping: " + error); - await enrichAndPersistCampaignWithError(messageObject, error); - } -} - -export async function handleStaffMapping(mappingArray: any[], campaignId: string, messageObject: any, type: string) { - await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.inprogress); - try { - logger.debug(`staff mapping count: ${mappingArray.length}`); - await processResourceOrFacilityOrUserMappingsInBatches(type, mappingArray, config?.batchSize || 100); - // for (const staffMapping of mappingArray) { - // const { resource, projectId, resouceBody, tenantId, startDate, endDate } = staffMapping; - // for (const resourceId of resource?.resourceIds) { - // promises.push(createStaffHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)) - // } - // } - } catch (error: any) { - logger.error("Error in staff mapping: " + error); - await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); - await enrichAndPersistCampaignWithError(messageObject, error); - throw new Error(error) - } - await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.completed); -} - -async function processResourceOrFacilityOrUserMappingsInBatches(type: string, mappingArray: any, batchSize: number) { - logger.info("Processing resource mappings in batches..."); - let promises: Promise[] = []; - let totalCreated = 0; // To keep track of the total number of created resources - let batchCount = 0; // To log batch-wise progress - // Determine the helper function to use based on the type - let createHelperFn: any; - if (type === 'resource') { - createHelperFn = createProjectResourceHelper; - } else if (type === 'staff') { - createHelperFn = createProjectStaffHelper; - } else if (type === 'facility') { - createHelperFn = createProjectFacilityHelper; - } else { - logger.error(`Unsupported type: ${type}`); - return; // Exit the function if the type is unsupported - } - - for (const mapping of mappingArray) { - const { resource, projectId, resouceBody, tenantId, startDate, endDate } = mapping; - - for (const resourceId of resource?.resourceIds || []) { - promises.push( - createHelperFn(resourceId, projectId, resouceBody, tenantId, startDate, endDate).then(() => { - totalCreated++; - }) - ); - - if (promises.length >= batchSize) { - batchCount++; - logger.info(`Processing batch ${batchCount} with ${promises.length} promises.`); - try { - await Promise.all(promises); // Wait for all promises in the current batch - } catch (error) { - logger.error(`Batch ${batchCount} failed:`, error); - throw error; // Ensure any error in the batch is propagated - } promises = []; // Reset the array for the next batch } } - } - - // Process any remaining promises - if (promises.length > 0) { - batchCount++; - logger.info(`Processing final batch ${batchCount} with ${promises.length} promises.`); - await Promise.all(promises); - } - - logger.info(`Processing completed. Total resources created: ${totalCreated}`); -} - - -export async function handleResourceMapping(mappingArray: any[], campaignId: any, messageObject: any, type: string) { - await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.inprogress); - try { - logger.debug(`Resource mapping count: ${mappingArray.length}`); - await processResourceOrFacilityOrUserMappingsInBatches(type, mappingArray, config?.batchSize || 100); - } catch (error: any) { - logger.error("Error in resource mapping: " + error); - await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); - await enrichAndPersistCampaignWithError(messageObject, error); - throw new Error(error) - } - await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.completed); -} - -export async function handleFacilityMapping(mappingArray: any, campaignId: any, messageObject: any, type: string) { - await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.inprogress); - try { - logger.debug(`facility mapping count: ${mappingArray.length}`); - // for (const mapping of mappingArray) { - // const { resource, projectId, resouceBody, tenantId } = mapping; - // for (const resourceId of resource?.resourceIds) { - // promises.push(createProjectFacilityHelper(resourceId, projectId, resouceBody, tenantId)); - // } - // } - await processResourceOrFacilityOrUserMappingsInBatches(type, mappingArray, config?.batchSize || 100); - } catch (error: any) { - logger.error("Error in facility mapping: " + error); - await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); - await enrichAndPersistCampaignWithError(messageObject, error); - throw new Error(error) - } - await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.completed); -} - -export async function processMapping(mappingObject: any) { - try { - if (mappingObject?.mappingArray && Array.isArray(mappingObject?.mappingArray) && mappingObject?.mappingArray?.length > 0) { - const resourceMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "resource"); - const facilityMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "facility"); - const staffMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "staff"); - await handleResourceMapping(resourceMappingArray, mappingObject?.CampaignDetails?.id, mappingObject, "resource"); - await handleFacilityMapping(facilityMappingArray, mappingObject?.CampaignDetails?.id, mappingObject, "facility"); - await handleStaffMapping(staffMappingArray, mappingObject?.CampaignDetails?.id, mappingObject, "staff"); - } - logger.info("Mapping completed successfully for campaign: " + mappingObject?.CampaignDetails?.id); - mappingObject.CampaignDetails.status = campaignStatuses.inprogress - if (mappingObject?.parentCampaign) { - await processResources(mappingObject); - mappingObject.CampaignDetails.campaignDetails.boundaries = [ - ...mappingObject.CampaignDetails.campaignDetails.boundaries, - ...mappingObject.parentCampaign.boundaries - ]; + var uncompletedResourceIds = resourceDetailsIds?.filter((x: any) => !completedResources.includes(x)); + logger.info("uncompletedResourceIds " + JSON.stringify(uncompletedResourceIds)); + logger.info("completedResources " + JSON.stringify(completedResources)); + if (uncompletedResourceIds?.length > 0) { + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + JSON.stringify(uncompletedResourceIds) + " is not validated after long wait. Check file"); } - const produceMessage: any = { - CampaignDetails: mappingObject?.CampaignDetails - } - await produceModifiedMessages(produceMessage, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC) - await persistTrack(mappingObject?.CampaignDetails?.id, processTrackTypes.campaignCreation, processTrackStatuses.completed) - } catch (error) { - logger.error("Error in campaign mapping: " + error); - await enrichAndPersistCampaignWithError(mappingObject, error); + await fetchAndMap(resources, messageObject); } } diff --git a/health-services/project-factory/src/server/utils/campaignUtils.ts b/health-services/project-factory/src/server/utils/campaignUtils.ts index 6a24266c28c..f2b4e1f37ca 100644 --- a/health-services/project-factory/src/server/utils/campaignUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignUtils.ts @@ -1,3800 +1,1825 @@ + import { defaultheader, httpRequest } from "./request"; import config from "../config/index"; -import { v4 as uuidv4 } from "uuid"; -import { produceModifiedMessages } from "../kafka/Producer"; -import { - confirmProjectParentCreation, - createProjectCampaignResourcData, - getCampaignSearchResponse, - getHierarchy, - handleResouceDetailsError, - projectCreate, - projectUpdateForTargets, -} from "../api/campaignApis"; -import { - getCampaignNumber, - createAndUploadFile, - createExcelSheet, - getAutoGeneratedBoundaryCodesHandler, - createBoundaryEntities, - getMDMSV1Data, - getTargetSheetDataAfterCode, - callMdmsTypeSchema, - getSheetDataFromWorksheet, - getTargetWorkbook, - createAndUploadJsonFile, - createBoundaryRelationship, - getSheetData, -} from "../api/genericApis"; +import { v4 as uuidv4 } from 'uuid'; +import { produceModifiedMessages } from '../kafka/Listener' +import { confirmProjectParentCreation, createProjectCampaignResourcData, getCampaignSearchResponse, getHierarchy, handleResouceDetailsError, projectCreate } from "../api/campaignApis"; +import { getCampaignNumber, createAndUploadFile, getSheetData, createExcelSheet, getAutoGeneratedBoundaryCodesHandler, createBoundaryEntities, createBoundaryRelationship, getMDMSV1Data, getTargetSheetDataAfterCode, callMdmsTypeSchema } from "../api/genericApis"; import { getFormattedStringForDebug, logger } from "./logger"; import createAndSearch from "../config/createAndSearch"; -import { - addDataToSheet, - createBoundaryDataMainSheet, - createReadMeSheet, - findMapValue, - getBoundaryRelationshipData, - getConfigurableColumnHeadersFromSchemaForTargetSheet, - getLocalizedHeaders, - getLocalizedMessagesHandler, - getMdmsDataBasedOnCampaignType, - modifyBoundaryData, - replicateRequest, - throwError, -} from "./genericUtils"; +import { addDataToSheet, createBoundaryDataMainSheet, createReadMeSheet, findMapValue, getBoundaryRelationshipData, getConfigurableColumnHeadersFromSchemaForTargetSheet, getLocalizedHeaders, getLocalizedMessagesHandler, getMdmsDataBasedOnCampaignType, modifyBoundaryData, replicateRequest, throwError } from "./genericUtils"; import { enrichProjectDetailsFromCampaignDetails } from "./transforms/projectTypeUtils"; import { executeQuery } from "./db"; -import { - campaignDetailsTransformer, - genericResourceTransformer, -} from "./transforms/searchResponseConstructor"; +import { campaignDetailsTransformer, genericResourceTransformer } from "./transforms/searchResponseConstructor"; import { transformAndCreateLocalisation } from "./transforms/localisationMessageConstructor"; -import { - campaignStatuses, - headingMapping, - processTrackStatuses, - processTrackTypes, - resourceDataStatuses, -} from "../config/constants"; -import { getBoundaryTabName } from "./boundaryUtils"; -import { - searchProjectTypeCampaignService, - updateProjectTypeCampaignService, -} from "../service/campaignManageService"; -import { - validateBoundaryOfResouces, - validateBoundarySheetDataInCreateFlow, -} from "../validators/campaignValidators"; -import { - getExcelWorkbookFromFileURL, - getNewExcelWorkbook, - lockTargetFields, - updateFontNameToRoboto, -} from "./excelUtils"; -import { - areBoundariesSame, - callGenerate, - callGenerateIfBoundariesOrCampaignTypeDiffer, -} from "./generateUtils"; -import { createProcessTracks, persistTrack } from "./processTrackUtils"; -import { - generateDynamicTargetHeaders, - isDynamicTargetTemplateForProjectType, - updateTargetColumnsIfDeliveryConditionsDifferForSMC, -} from "./targetUtils"; -import { - callGenerateWhenChildCampaigngetsCreated, - fetchProjectsWithBoundaryCodeAndReferenceId, - fetchProjectsWithProjectId, - getBoundariesFromCampaignSearchResponse, - getBoundaryProjectMappingFromParentCampaign, - getColumnIndexByHeader, - hideColumnsOfProcessedFile, - modifyNewSheetData, - unhideColumnsOfProcessedFile, -} from "./onGoingCampaignUpdateUtils"; -import { changeCreateDataForMicroplan, lockSheet } from "./microplanUtils"; -const _ = require("lodash"); -import { searchDataService } from "../service/dataManageService"; -import { searchMDMSDataViaV2Api } from "../api/coreApis"; -import { deleteRedisCacheKeysWithPrefix } from "./redisUtils"; -import { - fetchFacilityData, - fetchTargetData, - fetchUserData, -} from "./microplanIntergration"; +import { campaignStatuses, headingMapping, resourceDataStatuses } from "../config/constants"; +import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; +import { searchProjectTypeCampaignService } from "../service/campaignManageService"; +import { validateBoundaryOfResouces } from "../validators/campaignValidators"; +import { getExcelWorkbookFromFileURL, getNewExcelWorkbook, lockTargetFields, updateFontNameToRoboto } from "./excelUtils"; +const _ = require('lodash'); + + function updateRange(range: any, worksheet: any) { - let maxColumnIndex = 0; - - // Iterate through each row to find the last column with data - for (let row = range.s.r; row <= range.e.r; row++) { - const rowCells = worksheet.getRow(row + 1); // ExcelJS rows are 1-based - rowCells.eachCell((cell: any, colNumber: number) => { - if (cell.value !== undefined && colNumber > maxColumnIndex) { - maxColumnIndex = colNumber; - } - }); - } + let maxColumnIndex = 0; + + // Iterate through each row to find the last column with data + for (let row = range.s.r; row <= range.e.r; row++) { + const rowCells = worksheet.getRow(row + 1); // ExcelJS rows are 1-based + rowCells.eachCell((cell: any, colNumber: number) => { + if (cell.value !== undefined && colNumber > maxColumnIndex) { + maxColumnIndex = colNumber; + } + }); + } - // Update the end column of the range with the maximum column index found - range.e.c = maxColumnIndex; + // Update the end column of the range with the maximum column index found + range.e.c = maxColumnIndex; } function findAndChangeColumns(worksheet: any, columns: any) { - const firstRow = worksheet.getRow(1); - firstRow.eachCell((cell: any, colNumber: number) => { - if (cell.value === "#status#") { - columns.statusColumn = cell.address.replace(/\d+/g, ""); - // Set the cell color to green - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "CCCC00" }, - }; - // Delete status column cells in subsequent rows - worksheet.eachRow((row: any, rowIndex: number) => { - if (rowIndex > 1) { - const statusCell = row.getCell(colNumber); - statusCell.value = undefined; + const firstRow = worksheet.getRow(1); // First row (ExcelJS is 1-based) + firstRow.eachCell((cell: any, colNumber: number) => { + if (cell.value === '#status#') { + columns.statusColumn = cell.address.replace(/\d+/g, ''); + // Set the cell color to green + cell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: 'CCCC00' } + }; + // Delete status column cells in subsequent rows + worksheet.eachRow((row: any, rowIndex: number) => { + if (rowIndex > 1) { + const statusCell = row.getCell(colNumber); + statusCell.value = undefined; + } + }); } - }); - } - if (cell.value === "#errorDetails#") { - columns.errorDetailsColumn = cell.address.replace(/\d+/g, ""); - // Set the cell color to green - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "CCCC00" }, - }; - // Delete error details column cells in subsequent rows - worksheet.eachRow((row: any, rowIndex: number) => { - if (rowIndex > 1) { - const errorDetailsCell = row.getCell(colNumber); - errorDetailsCell.value = undefined; + if (cell.value === '#errorDetails#') { + columns.errorDetailsColumn = cell.address.replace(/\d+/g, ''); + // Set the cell color to green + cell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: 'CCCC00' } + }; + // Delete error details column cells in subsequent rows + worksheet.eachRow((row: any, rowIndex: number) => { + if (rowIndex > 1) { + const errorDetailsCell = row.getCell(colNumber); + errorDetailsCell.value = undefined; + } + }); } - }); - } - }); + }); } function makeColumns(worksheet: any, range: any, columns: any) { - // If the status column doesn't exist, calculate the next available column - if (!columns?.statusColumn) { - const emptyColumnIndex = range.e.c; - columns.statusColumn = String.fromCharCode(65 + (emptyColumnIndex + 1)); - const statusCell = worksheet.getCell(`${columns.statusColumn}1`); - statusCell.value = "#status#"; - statusCell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "CCCC00" }, - }; - statusCell.font = { bold: true }; - worksheet.getColumn(columns.statusColumn).width = 40; - } - - // Calculate errorDetails column one column to the right of status column - if (!columns?.errorDetailsColumn) { - columns.errorDetailsColumn = String.fromCharCode( - columns?.statusColumn.charCodeAt(0) + 1 - ); - const errorDetailsCell = worksheet.getCell( - `${columns.errorDetailsColumn}1` - ); - errorDetailsCell.value = "#errorDetails#"; - errorDetailsCell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "CCCC00" }, - }; - errorDetailsCell.font = { bold: true }; - worksheet.getColumn(columns.errorDetailsColumn).width = 40; - } + // If the status column doesn't exist, calculate the next available column + if (!columns?.statusColumn) { + const emptyColumnIndex = range.e.c; + columns.statusColumn = String.fromCharCode(65 + (emptyColumnIndex + 1)); + const statusCell = worksheet.getCell(`${columns.statusColumn}1`); + statusCell.value = '#status#'; + statusCell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: 'CCCC00' } + }; + statusCell.font = { bold: true }; + } + + // Calculate errorDetails column one column to the right of status column + if (!columns?.errorDetailsColumn) { + columns.errorDetailsColumn = String.fromCharCode(columns?.statusColumn.charCodeAt(0) + 1); + const errorDetailsCell = worksheet.getCell(`${columns.errorDetailsColumn}1`); + errorDetailsCell.value = '#errorDetails#'; + errorDetailsCell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: 'CCCC00' } + }; + errorDetailsCell.font = { bold: true }; + } } + function findColumns(worksheet: any) { - const range = { - s: { r: 0, c: 0 }, - e: { r: worksheet.rowCount - 1, c: worksheet.columnCount - 1 }, - }; + const range = { + s: { r: 0, c: 0 }, + e: { r: worksheet.rowCount - 1, c: worksheet.columnCount - 1 } + }; - // Check if the status column already exists in the first row - var columns = {}; + // Check if the status column already exists in the first row + var columns = {} - findAndChangeColumns(worksheet, columns); + findAndChangeColumns(worksheet, columns); - makeColumns(worksheet, range, columns); + makeColumns(worksheet, range, columns); - updateRange(range, worksheet); + updateRange(range, worksheet); - return columns; + return columns; } -function enrichErrors( - errorData: any, - worksheet: any, - statusColumn: any, - errorDetailsColumn: any, - additionalDetailsErrors: any, - createAndSearchConfig: any, - localizationMap?: { [key: string]: string } -) { - if (errorData) { - errorData.forEach((error: any) => { - const rowIndex = error.rowNumber; // ExcelJS rows are 1-based - const statusCell = worksheet.getCell(`${statusColumn}${rowIndex}`); - const errorDetailsCell = worksheet.getCell( - `${errorDetailsColumn}${rowIndex}` - ); - statusCell.value = error.status; - errorDetailsCell.value = error.errorDetails; - - if ( - error?.status && - !(error?.status === "CREATED" || error?.status === "VALID") - ) { - additionalDetailsErrors.push(error); - } - }); - if (errorData.some((error: any) => error?.status === "CREATED")) { - const uniqueIdentifierFirstRowCell = `${createAndSearchConfig?.uniqueIdentifierColumn}1`; - const columnName = getLocalizedName( - createAndSearchConfig?.uniqueIdentifierColumnName, - localizationMap - ); - const uniqueIdentifierCell = worksheet.getCell( - uniqueIdentifierFirstRowCell - ); - uniqueIdentifierCell.value = columnName; - - // Set the cell color to green - uniqueIdentifierCell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "ff9248" }, // Green color - }; - uniqueIdentifierCell.font = { bold: true }; - // Hide the unique identifier column - worksheet.getColumn( - createAndSearchConfig?.uniqueIdentifierColumn - ).hidden = true; - } - errorData.forEach((error: any) => { - const rowIndex = error.rowNumber; - if (error.isUniqueIdentifier) { - const uniqueIdentifierCell = worksheet.getCell( - `${createAndSearchConfig.uniqueIdentifierColumn}${rowIndex}` - ); - uniqueIdentifierCell.value = error.uniqueIdentifier; - if (createAndSearchConfig?.activeColumn) { - const activeCell = worksheet.getCell( - `${createAndSearchConfig.activeColumn}${rowIndex}` - ); - activeCell.value = "Active"; +function enrichErrors(errorData: any, worksheet: any, statusColumn: any, errorDetailsColumn: any, additionalDetailsErrors: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { + if (errorData) { + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; // ExcelJS rows are 1-based + const statusCell = worksheet.getCell(`${statusColumn}${rowIndex}`); + const errorDetailsCell = worksheet.getCell(`${errorDetailsColumn}${rowIndex}`); + statusCell.value = error.status; + errorDetailsCell.value = error.errorDetails; + + if ((error?.status) && !(error?.status === "CREATED" || error?.status === "VALID")) { + additionalDetailsErrors.push(error); + } + }); + if (errorData.some((error: any) => error?.status === "CREATED")) { + const uniqueIdentifierFirstRowCell = `${createAndSearchConfig?.uniqueIdentifierColumn}1`; + const columnName = getLocalizedName(createAndSearchConfig?.uniqueIdentifierColumnName, localizationMap); + const uniqueIdentifierCell = worksheet.getCell(uniqueIdentifierFirstRowCell); + uniqueIdentifierCell.value = columnName; + + // Set the cell color to green + uniqueIdentifierCell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: 'ff9248' } // Green color + }; + uniqueIdentifierCell.font = { bold: true }; + // Hide the unique identifier column + worksheet.getColumn(createAndSearchConfig?.uniqueIdentifierColumn).hidden = true; } - } - }); - } + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; + if (error.isUniqueIdentifier) { + const uniqueIdentifierCell = worksheet.getCell(`${createAndSearchConfig.uniqueIdentifierColumn}${rowIndex}`); + uniqueIdentifierCell.value = error.uniqueIdentifier; + if (createAndSearchConfig?.activeColumn) { + const activeCell = worksheet.getCell(`${createAndSearchConfig.activeColumn}${rowIndex}`); + activeCell.value = "Active"; + } + } + }); + } } -function enrichActiveAndUUidColumn( - worksheet: any, - createAndSearchConfig: any, - request: any -) { - if ( - createAndSearchConfig?.activeColumn && - request?.body?.dataToCreate && - request?.body?.dataToCreate?.length > 0 && - request?.body?.ResourceDetails?.type == "user" - ) { - const dataToCreate = request.body.dataToCreate; - for (const data of dataToCreate) { - const rowNumber = data["!row#number!"]; - const activeCell = worksheet.getCell( - `${createAndSearchConfig?.activeColumn}${rowNumber}` - ); - const uniqueIdentifierCell = worksheet.getCell( - `${createAndSearchConfig?.uniqueIdentifierColumn}${rowNumber}` - ); - activeCell.value = "Active"; - uniqueIdentifierCell.value = data["userServiceUuid"]; - } - } -} - -function deterMineLastColumnAndEnrichUserDetails( - worksheet: any, - errorDetailsColumn: number, - userNameAndPassword: - | { rowNumber: number; userName: string; password: string }[] - | undefined, - request: any, - createAndSearchConfig: { uniqueIdentifierColumn?: number } -): string { - // Determine the last column - let lastColumn: any = errorDetailsColumn; - if (createAndSearchConfig?.uniqueIdentifierColumn !== undefined) { - lastColumn = - createAndSearchConfig?.uniqueIdentifierColumn > errorDetailsColumn - ? createAndSearchConfig?.uniqueIdentifierColumn - : errorDetailsColumn; - } - - // Default columns - let usernameColumn = "J"; - let passwordColumn = "K"; - - // Update columns if the request indicates a different source - if ( - request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" - ) { - usernameColumn = "F"; - passwordColumn = "G"; - } - - // Populate username and password columns if data is provided - if (userNameAndPassword) { - // Set headers with formatting - const setCellHeader = (cell: string) => { - worksheet.getCell(cell).value = - cell === usernameColumn + "1" ? "UserName" : "Password"; - worksheet.getCell(cell).fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "ff9248" }, // Green color - }; - worksheet.getCell(cell).font = { bold: true }; - const columnLetter = cell.replace(/\d+$/, ""); - worksheet.getColumn(columnLetter).width = 40; - }; +function enrichActiveColumn(worksheet: any, createAndSearchConfig: any, request: any) { + if (createAndSearchConfig?.activeColumn && request?.body?.dataToCreate) { + const dataToCreate = request.body.dataToCreate; + for (const data of dataToCreate) { + const rowNumber = data['!row#number!']; + const activeCell = worksheet.getCell(`${createAndSearchConfig?.activeColumn}${rowNumber}`); + activeCell.value = "Active"; + } + } +} - setCellHeader(usernameColumn + "1"); - setCellHeader(passwordColumn + "1"); +function deterMineLastColumnAndEnrichUserDetails(worksheet: any, errorDetailsColumn: any, userNameAndPassword: any, request: any, createAndSearchConfig: any) { + let lastColumn = errorDetailsColumn; + if (createAndSearchConfig?.uniqueIdentifierColumn !== undefined) { + lastColumn = createAndSearchConfig?.uniqueIdentifierColumn > errorDetailsColumn ? + createAndSearchConfig?.uniqueIdentifierColumn : + errorDetailsColumn; + } - // Set values - userNameAndPassword.forEach((data) => { - const rowIndex = data.rowNumber; - worksheet.getCell(`${usernameColumn}${rowIndex}`).value = data.userName; - worksheet.getCell(`${passwordColumn}${rowIndex}`).value = data.password; - }); + if (userNameAndPassword) { + worksheet.getCell("I1").value = "UserName"; + worksheet.getCell("J1").value = "Password"; + + // Set the fill color to green for cell I1 + worksheet.getCell("I1").fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: 'ff9248' } // Green color + }; + worksheet.getCell("I1").font = { bold: true }; - // Update lastColumn based on the password column - lastColumn = passwordColumn; - } + // Set the fill color to green for cell J1 + worksheet.getCell("J1").fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: 'ff9248' } // Green color + }; + worksheet.getCell("J1").font = { bold: true }; + + userNameAndPassword.forEach((data: any) => { + const rowIndex = data.rowNumber; + worksheet.getCell(`I${rowIndex}`).value = data?.userName; + worksheet.getCell(`J${rowIndex}`).value = data?.password; + }); + + lastColumn = "J"; + request.body.userNameAndPassword = undefined; + } - return lastColumn; + return lastColumn; } function adjustRef(worksheet: any, lastColumn: any) { - const range = getSheetDataFromWorksheet(worksheet).filter( - (row: any) => row - ).length; // Get the number of used rows - worksheet.views = [ - { state: "frozen", ySplit: 1, topLeftCell: "A2", activeCell: "A2" }, - ]; - worksheet.autoFilter = { - from: { - row: 1, - column: 1, - }, - to: { - row: range, - column: worksheet.getColumn(lastColumn).number, - }, - }; -} - -function processErrorData( - request: any, - createAndSearchConfig: any, - workbook: any, - sheetName: any, - localizationMap?: { [key: string]: string } -) { - const worksheet = workbook.getWorksheet(sheetName); - var errorData = request.body.sheetErrorDetails; - const userNameAndPassword = request.body.userNameAndPassword; - const columns: any = findColumns(worksheet); - const statusColumn = columns.statusColumn; - const errorDetailsColumn = columns.errorDetailsColumn; - const additionalDetailsErrors: any[] = []; - errorData = mergeErrors(errorData); - enrichErrors( - errorData, - worksheet, - statusColumn, - errorDetailsColumn, - additionalDetailsErrors, - createAndSearchConfig, - localizationMap - ); - enrichActiveAndUUidColumn(worksheet, createAndSearchConfig, request); - - request.body.additionalDetailsErrors = request?.body?.additionalDetailsErrors - ? request?.body?.additionalDetailsErrors.concat(additionalDetailsErrors) - : additionalDetailsErrors; - - // Determine the last column to set the worksheet ref - const lastColumn = deterMineLastColumnAndEnrichUserDetails( - worksheet, - errorDetailsColumn, - userNameAndPassword, - request, - createAndSearchConfig - ); - - // Adjust the worksheet ref to include the last column - adjustRef(worksheet, lastColumn); - updateFontNameToRoboto(worksheet); - - workbook.xlsx.writeBuffer(); -} - -function mergeErrors(errorData: any) { - const errorMap: any = {}; - - errorData.forEach((item: any) => { - const { rowNumber, sheetName, status, errorDetails, ...rest } = item; - - // If the rowNumber already exists, merge the errorDetails - if (errorMap[rowNumber]) { - errorMap[rowNumber].errorDetails += "; " + errorDetails; - } else { - // If not, add a new entry - errorMap[rowNumber] = { - rowNumber, - sheetName, - status, - errorDetails, - ...rest, - }; - } - }); - - // Convert the errorMap back into an array - return Object.values(errorMap); -} - -function processErrorDataForEachSheets( - request: any, - createAndSearchConfig: any, - workbook: any, - sheetName: any -) { - const desiredSheet = workbook.getWorksheet(sheetName); - const columns: any = findColumns(desiredSheet); - const statusColumn = columns.statusColumn; - const errorDetailsColumn = columns.errorDetailsColumn; - const userNameAndPassword = request?.body?.userNameAndPassword; - - var errorData = request.body.sheetErrorDetails.filter( - (error: any) => error.sheetName === sheetName - ); - const additionalDetailsErrors: any = []; - errorData = mergeErrors(errorData); - if (errorData) { - errorData.forEach((error: any) => { - const rowIndex = error.rowNumber; - if (error.isUniqueIdentifier) { - const uniqueIdentifierCell = - createAndSearchConfig.uniqueIdentifierColumn + rowIndex; - desiredSheet.getCell(uniqueIdentifierCell).value = - error.uniqueIdentifier; - } - - const statusCell = statusColumn + rowIndex; - const errorDetailsCell = errorDetailsColumn + rowIndex; - desiredSheet.getCell(statusCell).value = error.status; - desiredSheet.getCell(errorDetailsCell).value = error.errorDetails; - - if (!(error.status === "CREATED" || error.status === "VALID")) { - additionalDetailsErrors.push(error); - } - }); - } - if (userNameAndPassword) { - var newUserNameAndPassword: any = []; - for (const data of userNameAndPassword) { - const rowArray = data.rowNumber; - for (let i = 0; i < rowArray.length; i++) { - if (rowArray[i].sheetName == sheetName) { - newUserNameAndPassword.push({ ...data, rowNumber: rowArray[i].row }); + const range = worksheet.getSheetValues().filter((row: any) => row).length; // Get the number of used rows + worksheet.views = [ + { state: 'frozen', ySplit: 1, topLeftCell: 'A2', activeCell: 'A2' } + ]; + worksheet.autoFilter = { + from: { + row: 1, + column: 1 + }, + to: { + row: range, + column: worksheet.getColumn(lastColumn).number } - } - } - } - deterMineLastColumnAndEnrichUserDetails( - desiredSheet, - errorDetailsColumn, - newUserNameAndPassword, - request, - createAndSearchConfig - ); - request.body.additionalDetailsErrors = request?.body?.additionalDetailsErrors - ? request?.body?.additionalDetailsErrors.concat(additionalDetailsErrors) - : additionalDetailsErrors; - updateFontNameToRoboto(desiredSheet); - workbook.worksheets[sheetName] = desiredSheet; -} - -async function updateStatusFile( - request: any, - localizationMap?: { [key: string]: string } -) { - const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; - const tenantId = request?.body?.ResourceDetails?.tenantId; - const createAndSearchConfig = - createAndSearch[request?.body?.ResourceDetails?.type]; - const fileResponse = await httpRequest( - config.host.filestore + config.paths.filestore + "/url", - {}, - { tenantId: tenantId, fileStoreIds: fileStoreId }, - "get" - ); - const isLockSheetNeeded = - request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" - ? true - : false; - - if (!fileResponse?.fileStoreIds?.[0]?.url) { - throwError("FILE", 500, "INVALID_FILE"); - } - const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; - const sheetName = createAndSearchConfig?.parseArrayConfig?.sheetName; - const localizedSheetName = getLocalizedName(sheetName, localizationMap); - const workbook: any = await getExcelWorkbookFromFileURL( - fileUrl, - localizedSheetName - ); - const worksheet: any = workbook.getWorksheet(localizedSheetName); - if (request?.body?.ResourceDetails?.type == "user") { - const columnsToUnhide = ["G", "H", "J", "K"]; - unhideColumnsOfProcessedFile(worksheet, columnsToUnhide); - } - processErrorData( - request, - createAndSearchConfig, - workbook, - localizedSheetName, - localizationMap - ); - - // Set column widths - const columnWidths = Array(12).fill({ width: 30 }); - columnWidths.forEach((colWidth, index) => { - if (worksheet.getColumn(index + 1)) { - worksheet.getColumn(index + 1).width = colWidth.width; - } - }); - if (isLockSheetNeeded) lockSheet(request, workbook); - const responseData = await createAndUploadFile(workbook, request); - - logger.info("File updated successfully:" + JSON.stringify(responseData)); - if (responseData?.[0]?.fileStoreId) { - request.body.ResourceDetails.processedFileStoreId = - responseData?.[0]?.fileStoreId; - } else { - throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); - } -} -async function updateStatusFileForEachSheets( - request: any, - localizationMap?: { [key: string]: string } -) { - const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; - const tenantId = request?.body?.ResourceDetails?.tenantId; - const createAndSearchConfig = - createAndSearch[request?.body?.ResourceDetails?.type]; - const fileResponse = await httpRequest( - config.host.filestore + config.paths.filestore + "/url", - {}, - { tenantId: tenantId, fileStoreIds: fileStoreId }, - "get" - ); - const isLockSheetNeeded = - request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" - ? true - : false; - - if (!fileResponse?.fileStoreIds?.[0]?.url) { - throwError("FILE", 500, "INVALID_FILE"); - } - - const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; - - const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, ""); - - const sheetNames = workbook.worksheets.map( - (worksheet: any) => worksheet.name - ); - const localizedSheetNames = getLocalizedHeaders(sheetNames, localizationMap); - - const sheetErrorDetails = request?.body?.sheetErrorDetails; - if (sheetErrorDetails && sheetErrorDetails?.length > 0) { - const firstError = sheetErrorDetails[0]; - if (Array.isArray(firstError?.rowNumber)) { - var newSheetErrorDetails: any = []; - for (const error of sheetErrorDetails) { - for (let i = 0; i < error.rowNumber.length; i++) { - newSheetErrorDetails.push({ - ...error, - rowNumber: error.rowNumber[i]?.row, - sheetName: error.rowNumber[i]?.sheetName, - }); + }; +} + +function processErrorData(request: any, createAndSearchConfig: any, workbook: any, sheetName: any, localizationMap?: { [key: string]: string }) { + const worksheet = workbook.getWorksheet(sheetName); + const errorData = request.body.sheetErrorDetails; + const userNameAndPassword = request.body.userNameAndPassword; + const columns: any = findColumns(worksheet); + const statusColumn = columns.statusColumn; + const errorDetailsColumn = columns.errorDetailsColumn; + const additionalDetailsErrors: any[] = []; + + enrichErrors(errorData, worksheet, statusColumn, errorDetailsColumn, additionalDetailsErrors, createAndSearchConfig, localizationMap); + enrichActiveColumn(worksheet, createAndSearchConfig, request); + + request.body.additionalDetailsErrors = additionalDetailsErrors; + + // Determine the last column to set the worksheet ref + const lastColumn = deterMineLastColumnAndEnrichUserDetails(worksheet, errorDetailsColumn, userNameAndPassword, request, createAndSearchConfig); + + // Adjust the worksheet ref to include the last column + adjustRef(worksheet, lastColumn); + updateFontNameToRoboto(worksheet) + + workbook.xlsx.writeBuffer(); +} + + +function processErrorDataForTargets(request: any, createAndSearchConfig: any, workbook: any, sheetName: any) { + const desiredSheet = workbook.getWorksheet(sheetName); + const columns: any = findColumns(desiredSheet); + const statusColumn = columns.statusColumn; + const errorDetailsColumn = columns.errorDetailsColumn; + + const errorData = request.body.sheetErrorDetails.filter((error: any) => error.sheetName === sheetName); + const additionalDetailsErrors: any = []; + + if (errorData) { + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; + if (error.isUniqueIdentifier) { + const uniqueIdentifierCell = createAndSearchConfig.uniqueIdentifierColumn + (rowIndex); + desiredSheet.getCell(uniqueIdentifierCell).value = error.uniqueIdentifier; + } + + const statusCell = statusColumn + (rowIndex); + const errorDetailsCell = errorDetailsColumn + (rowIndex); + desiredSheet.getCell(statusCell).value = error.status; + desiredSheet.getCell(errorDetailsCell).value = error.errorDetails; + + if (!(error.status === "CREATED" || error.status === "VALID")) { + additionalDetailsErrors.push(error); + } + }); + } + + request.body.additionalDetailsErrors = additionalDetailsErrors; + updateFontNameToRoboto(desiredSheet) + workbook.worksheets[sheetName] = desiredSheet; +} + +async function updateStatusFile(request: any, localizationMap?: { [key: string]: string }) { + const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; + const tenantId = request?.body?.ResourceDetails?.tenantId; + const createAndSearchConfig = createAndSearch[request?.body?.ResourceDetails?.type]; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); + + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "INVALID_FILE"); + } + const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; + const sheetName = createAndSearchConfig?.parseArrayConfig?.sheetName; + const localizedSheetName = getLocalizedName(sheetName, localizationMap); + const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, localizedSheetName); + const worksheet: any = workbook.getWorksheet(localizedSheetName); + processErrorData(request, createAndSearchConfig, workbook, localizedSheetName, localizationMap); + + // Set column widths + const columnWidths = Array(12).fill({ width: 30 }); + columnWidths.forEach((colWidth, index) => { + if (worksheet.getColumn(index + 1)) { + worksheet.getColumn(index + 1).width = colWidth.width; } - } - request.body.sheetErrorDetails = newSheetErrorDetails; - } - } - - localizedSheetNames.forEach((sheetName: any) => { - if ( - sheetName !== - getLocalizedName(config?.boundary?.boundaryTab, localizationMap) && - sheetName !== - getLocalizedName(config.values.readMeTab, localizationMap) && - sheetName !== - getLocalizedName("USER_MICROPLAN_SHEET_ROLES", localizationMap) - ) { - processErrorDataForEachSheets( - request, - createAndSearchConfig, - workbook, - sheetName - ); - } - }); - if (isLockSheetNeeded) lockSheet(request, workbook); - const responseData = await createAndUploadFile(workbook, request); - logger.info("File updated successfully:" + JSON.stringify(responseData)); - if (responseData?.[0]?.fileStoreId) { - request.body.ResourceDetails.processedFileStoreId = - responseData?.[0]?.fileStoreId; - } else { - throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); - } + }); + + const responseData = await createAndUploadFile(workbook, request); + + logger.info('File updated successfully:' + JSON.stringify(responseData)); + if (responseData?.[0]?.fileStoreId) { + request.body.ResourceDetails.processedFileStoreId = responseData?.[0]?.fileStoreId; + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } } +async function updateStatusFileForTargets(request: any, localizationMap?: { [key: string]: string }) { + const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; + const tenantId = request?.body?.ResourceDetails?.tenantId; + const createAndSearchConfig = createAndSearch[request?.body?.ResourceDetails?.type]; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); -function convertToType(dataToSet: any, type: any) { - switch (type) { - case "string": - return String(dataToSet); - case "number": - return Number(dataToSet); - case "boolean": - // Convert to boolean assuming any truthy value should be true and falsy should be false - return Boolean(dataToSet); - // Add more cases if needed for other types - default: - // If type is not recognized, keep dataToSet as it is - return dataToSet; - } + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "INVALID_FILE"); + } + + + const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; + + const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, ""); + + const sheetNames = workbook.worksheets.map((worksheet: any) => worksheet.name); + const localizedSheetNames = getLocalizedHeaders(sheetNames, localizationMap); + + localizedSheetNames.forEach((sheetName: any) => { + if (sheetName !== getLocalizedName(config?.boundary?.boundaryTab, localizationMap) && sheetName !== getLocalizedName(config.values.readMeTab, localizationMap)) { + processErrorDataForTargets(request, createAndSearchConfig, workbook, sheetName); + } + }); + + const responseData = await createAndUploadFile(workbook, request); + logger.info('File updated successfully:' + JSON.stringify(responseData)); + if (responseData?.[0]?.fileStoreId) { + request.body.ResourceDetails.processedFileStoreId = responseData?.[0]?.fileStoreId; + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } } -function setTenantId( - resultantElement: any, - requestBody: any, - createAndSearchConfig: any -) { - if (createAndSearchConfig?.parseArrayConfig?.tenantId) { - const tenantId = _.get( - requestBody, - createAndSearchConfig?.parseArrayConfig?.tenantId?.getValueViaPath - ); - _.set( - resultantElement, - createAndSearchConfig?.parseArrayConfig?.tenantId?.resultantPath, - tenantId - ); - } + +function convertToType(dataToSet: any, type: any) { + switch (type) { + case "string": + return String(dataToSet); + case "number": + return Number(dataToSet); + case "boolean": + // Convert to boolean assuming any truthy value should be true and falsy should be false + return Boolean(dataToSet); + // Add more cases if needed for other types + default: + // If type is not recognized, keep dataToSet as it is + return dataToSet; + } } -async function processData( - request: any, - dataFromSheet: any[], - createAndSearchConfig: any, - localizationMap?: { [key: string]: string } +function setTenantId( + resultantElement: any, + requestBody: any, + createAndSearchConfig: any ) { - const parseLogic = createAndSearchConfig?.parseArrayConfig?.parseLogic; - const requiresToSearchFromSheet = - createAndSearchConfig?.requiresToSearchFromSheet; - const isSourceMicroplan = - request?.body?.ResourceDetails?.additionalDetails?.source == "microplan"; - var createData = [], - searchData = []; - for (const data of dataFromSheet) { - const resultantElement: any = {}; - for (const element of parseLogic) { - if (element?.resultantPath) { - const localizedSheetColumnName = getLocalizedName( - element.sheetColumnName, - localizationMap - ); - let dataToSet = _.get(data, localizedSheetColumnName); - if (element.conversionCondition) { - dataToSet = element.conversionCondition[dataToSet]; + if (createAndSearchConfig?.parseArrayConfig?.tenantId) { + const tenantId = _.get(requestBody, createAndSearchConfig?.parseArrayConfig?.tenantId?.getValueViaPath); + _.set(resultantElement, createAndSearchConfig?.parseArrayConfig?.tenantId?.resultantPath, tenantId); + } + +} + + +async function processData(request: any, dataFromSheet: any[], createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { + const parseLogic = createAndSearchConfig?.parseArrayConfig?.parseLogic; + const requiresToSearchFromSheet = createAndSearchConfig?.requiresToSearchFromSheet; + var createData = [], searchData = []; + for (const data of dataFromSheet) { + const resultantElement: any = {}; + for (const element of parseLogic) { + if (element?.resultantPath) { + const localizedSheetColumnName = getLocalizedName(element.sheetColumnName, localizationMap); + let dataToSet = _.get(data, localizedSheetColumnName); + if (element.conversionCondition) { + dataToSet = element.conversionCondition[dataToSet]; + } + if (element.type) { + dataToSet = convertToType(dataToSet, element.type); + } + _.set(resultantElement, element.resultantPath, dataToSet); + } } - if (element.type) { - dataToSet = convertToType(dataToSet, element.type); + resultantElement["!row#number!"] = data["!row#number!"]; + var addToCreate = true; + if (requiresToSearchFromSheet) { + for (const key of requiresToSearchFromSheet) { + const localizedSheetColumnName = getLocalizedName(key.sheetColumnName, localizationMap); + if (data[localizedSheetColumnName]) { + searchData.push(resultantElement) + addToCreate = false; + break; + } + } } - _.set(resultantElement, element.resultantPath, dataToSet); - } - } - resultantElement["!row#number!"] = data["!row#number!"]; - var addToCreate = true; - if (requiresToSearchFromSheet) { - for (const key of requiresToSearchFromSheet) { - const localizedSheetColumnName = getLocalizedName( - key.sheetColumnName, - localizationMap - ); - if (data[localizedSheetColumnName]) { - if (isSourceMicroplan) { - changeCreateDataForMicroplan( - request, - resultantElement, - data, - localizationMap - ); - } - searchData.push(resultantElement); - addToCreate = false; - break; + if (addToCreate) { + createData.push(resultantElement) } - } - } - if (addToCreate) { - if (isSourceMicroplan) { - changeCreateDataForMicroplan( - request, - resultantElement, - data, - localizationMap - ); - } - createData.push(resultantElement); - } - } - return { searchData, createData }; -} - -function setTenantIdAndSegregate( - processedData: any, - createAndSearchConfig: any, - requestBody: any -) { - for (const resultantElement of processedData.createData) { - setTenantId(resultantElement, requestBody, createAndSearchConfig); - } - for (const resultantElement of processedData.searchData) { - setTenantId(resultantElement, requestBody, createAndSearchConfig); - } - return processedData; + } + return { searchData, createData }; +} + +function setTenantIdAndSegregate(processedData: any, createAndSearchConfig: any, requestBody: any) { + for (const resultantElement of processedData.createData) { + setTenantId(resultantElement, requestBody, createAndSearchConfig); + } + for (const resultantElement of processedData.searchData) { + setTenantId(resultantElement, requestBody, createAndSearchConfig); + } + return processedData; } // Original function divided into two parts -async function convertToTypeData( - request: any, - dataFromSheet: any[], - createAndSearchConfig: any, - requestBody: any, - localizationMap?: { [key: string]: string } -) { - const processedData = await processData( - request, - dataFromSheet, - createAndSearchConfig, - localizationMap - ); - return setTenantIdAndSegregate( - processedData, - createAndSearchConfig, - requestBody - ); +async function convertToTypeData(request: any, dataFromSheet: any[], createAndSearchConfig: any, requestBody: any, localizationMap?: { [key: string]: string }) { + const processedData = await processData(request, dataFromSheet, createAndSearchConfig, localizationMap); + return setTenantIdAndSegregate(processedData, createAndSearchConfig, requestBody); } function updateActivityResourceId(request: any) { - if (request?.body?.Activities && Array.isArray(request?.body?.Activities)) { - for (const activity of request?.body?.Activities) { - activity.resourceDetailsId = request?.body?.ResourceDetails?.id; + if (request?.body?.Activities && Array.isArray(request?.body?.Activities)) { + for (const activity of request?.body?.Activities) { + activity.resourceDetailsId = request?.body?.ResourceDetails?.id + } } - } } -async function generateProcessedFileAndPersist( - request: any, - localizationMap?: { [key: string]: string } -) { - if ( - request.body.ResourceDetails.type == "boundaryWithTarget" || - (request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" && - request.body.ResourceDetails.type == "user") - ) { - await updateStatusFileForEachSheets(request, localizationMap); - } else { - if ( - request.body.ResourceDetails.type !== "boundary" && - request.body.ResourceDetails.type !== "boundaryManagement" - ) { - await updateStatusFile(request, localizationMap); - } - } - updateActivityResourceId(request); - request.body.ResourceDetails = { - ...request?.body?.ResourceDetails, - status: - request.body.ResourceDetails.status != resourceDataStatuses.invalid - ? resourceDataStatuses.completed - : resourceDataStatuses.invalid, - auditDetails: { - ...request?.body?.ResourceDetails?.auditDetails, - lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, - lastModifiedTime: Date.now(), - }, - additionalDetails: { - ...request?.body?.ResourceDetails?.additionalDetails, - sheetErrors: request?.body?.additionalDetailsErrors, - source: - request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" - ? "microplan" - : null, - }, - }; - if ( - request?.body?.ResourceDetails?.status === resourceDataStatuses.completed && - request?.body?.ResourceDetails?.type === "boundaryManagement" - ) { - // delete redis cache key with prefix boundaryRelatiionshipSearch - await deleteRedisCacheKeysWithPrefix("boundaryRelationShipSearch"); - - logger.info( - "calling generate after boundary data uploaded under type boundary management" - ); - const newRequestBody = { - RequestInfo: request?.body?.RequestInfo, - }; - const params = { - type: request?.body?.ResourceDetails?.type, - tenantId: request?.body?.ResourceDetails?.tenantId, - forceUpdate: "true", - hierarchyType: request?.body?.ResourceDetails?.hierarchyType, - campaignId: "default", - }; - const newRequestBoundary = replicateRequest( - request, - newRequestBody, - params - ); - setTimeout(async () => { - // Code to be executed after 10 seconds - logger.info("Timeout of 10 sec after boundary data creation"); - await callGenerate( - newRequestBoundary, - request?.body?.ResourceDetails?.type - ); - }, 10000); - } - const persistMessage: any = { ResourceDetails: request.body.ResourceDetails }; - if (request?.body?.ResourceDetails?.action == "create") { - persistMessage.ResourceDetails.additionalDetails = { - source: - request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" - ? "microplan" - : null, - fileName: - request?.body?.ResourceDetails?.additionalDetails?.fileName || null, +async function generateProcessedFileAndPersist(request: any, localizationMap?: { [key: string]: string }) { + if (request.body.ResourceDetails.type == 'boundaryWithTarget') { + await updateStatusFileForTargets(request, localizationMap); + } else { + if (request.body.ResourceDetails.type !== "boundary") { + await updateStatusFile(request, localizationMap); + } + } + updateActivityResourceId(request); + request.body.ResourceDetails = { + ...request?.body?.ResourceDetails, + status: request.body.ResourceDetails.status != resourceDataStatuses.invalid ? resourceDataStatuses.completed : resourceDataStatuses.invalid, + auditDetails: { + ...request?.body?.ResourceDetails?.auditDetails, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now() + }, + additionalDetails: { ...request?.body?.ResourceDetails?.additionalDetails, sheetErrors: request?.body?.additionalDetailsErrors } || {} }; - } - await produceModifiedMessages( - persistMessage, - config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC - ); - logger.info( - `ResourceDetails to persist : ${request.body.ResourceDetails.type}` - ); - if ( - request?.body?.Activities && - Array.isArray(request?.body?.Activities) && - request?.body?.Activities.length > 0 - ) { - logger.info("Activities to persist : "); - logger.debug(getFormattedStringForDebug(request?.body?.Activities)); - logger.info(`Waiting for 2 seconds`); - await new Promise((resolve) => setTimeout(resolve, 2000)); - const activities = request?.body?.Activities; - for (let i = 0; i < activities.length; i += 10) { - const chunk = activities.slice(i, Math.min(i + 10, activities.length)); - const activityObject: any = { Activities: chunk }; - await produceModifiedMessages( - activityObject, - config.kafka.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC - ); - } - } + const persistMessage: any = { ResourceDetails: request.body.ResourceDetails } + if (request?.body?.ResourceDetails?.action == "create") { + persistMessage.ResourceDetails.additionalDetails = {} + } + produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); + logger.info(`ResourceDetails to persist : ${request.body.ResourceDetails.type}`); + if (request?.body?.Activities && Array.isArray(request?.body?.Activities && request?.body?.Activities.length > 0)) { + logger.info("Activities to persist : ") + logger.debug(getFormattedStringForDebug(request?.body?.Activities)); + logger.info(`Waiting for 2 seconds`); + await new Promise(resolve => setTimeout(resolve, 2000)); + produceModifiedMessages(request?.body, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + } } function getRootBoundaryCode(boundaries: any[] = []) { - for (const boundary of boundaries) { - if (boundary.isRoot) { - return boundary.code; + for (const boundary of boundaries) { + if (boundary.isRoot) { + return boundary.code; + } } - } - return ""; + return ""; } function enrichRootProjectId(requestBody: any) { - var rootBoundary; - for (const boundary of requestBody?.boundariesCombined) { - if (boundary?.isRoot) { - rootBoundary = boundary?.code; - break; + var rootBoundary; + for (const boundary of requestBody?.CampaignDetails?.boundaries) { + if (boundary?.isRoot) { + rootBoundary = boundary?.code + break; + } } - } - if (rootBoundary) { - requestBody.CampaignDetails.projectId = - requestBody?.boundaryProjectMapping?.[rootBoundary]?.projectId || null; - } - requestBody.CampaignDetails.projectId = - requestBody.CampaignDetails.projectId || null; + if (rootBoundary) { + requestBody.CampaignDetails.projectId = requestBody?.boundaryProjectMapping?.[rootBoundary]?.projectId || null + } + requestBody.CampaignDetails.projectId = requestBody.CampaignDetails.projectId || null } async function enrichAndPersistCampaignWithError(requestBody: any, error: any) { - if (requestBody?.parentCampaign) { - await makeParentInactiveOrActive(requestBody, true); - } - requestBody.CampaignDetails = requestBody?.CampaignDetails || {}; - const action = requestBody?.CampaignDetails?.action; - requestBody.CampaignDetails.campaignNumber = - requestBody?.CampaignDetails?.campaignNumber || null; - requestBody.CampaignDetails.campaignDetails = requestBody?.CampaignDetails - ?.campaignDetails || { - deliveryRules: requestBody?.CampaignDetails?.deliveryRules, - resources: requestBody?.CampaignDetails?.resources || [], - boundaries: requestBody?.CampaignDetails?.boundaries || [], - }; - requestBody.CampaignDetails.status = campaignStatuses?.failed; - // requestBody.CampaignDetails.isActive = false; - requestBody.CampaignDetails.boundaryCode = - getRootBoundaryCode(requestBody?.boundariesCombined) || null; - requestBody.CampaignDetails.projectType = - requestBody?.CampaignDetails?.projectType || null; - requestBody.CampaignDetails.hierarchyType = - requestBody?.CampaignDetails?.hierarchyType || null; - requestBody.CampaignDetails.additionalDetails = - requestBody?.CampaignDetails?.additionalDetails || {}; - requestBody.CampaignDetails.startDate = - requestBody?.CampaignDetails?.startDate || null; - requestBody.CampaignDetails.endDate = - requestBody?.CampaignDetails?.endDate || null; - requestBody.CampaignDetails.auditDetails = { - createdBy: requestBody?.RequestInfo?.userInfo?.uuid, - createdTime: Date.now(), - lastModifiedBy: requestBody?.RequestInfo?.userInfo?.uuid, - lastModifiedTime: Date.now(), - }; - if (action == "create" && !requestBody?.CampaignDetails?.projectId) { - enrichRootProjectId(requestBody); - } else if (!requestBody?.CampaignDetails?.projectId) { - requestBody.CampaignDetails.projectId = null; - } - requestBody.CampaignDetails.additionalDetails = { - ...requestBody?.CampaignDetails?.additionalDetails, - error: String( - error?.message + (error?.description ? ` : ${error?.description}` : "") || - error - ), - }; - const topic = config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC; - // wait for 2 seconds - logger.info(`Waiting for 2 seconds to persist errors`); - await new Promise((resolve) => setTimeout(resolve, 2000)); - const produceMessage: any = { CampaignDetails: requestBody.CampaignDetails }; - await produceModifiedMessages(produceMessage, topic); - await persistTrack( - requestBody?.CampaignDetails?.id, - processTrackTypes.error, - processTrackStatuses.failed, - { - error: String( - error?.message + - (error?.description ? ` : ${error?.description}` : "") || error - ), - } - ); - delete requestBody.CampaignDetails.campaignDetails; -} - -async function enrichAndPersistCampaignForCreate( - request: any, - firstPersist: boolean = false -) { - const action = request?.body?.CampaignDetails?.action; - if (firstPersist) { - if (!request?.body?.parentCampaign) { - request.body.CampaignDetails.campaignNumber = await getCampaignNumber( - request.body, - "CMP-[cy:yyyy-MM-dd]-[SEQ_EG_CMP_ID]", - "campaign.number", - request?.body?.CampaignDetails?.tenantId - ); - } else { - request.body.CampaignDetails.campaignNumber = - request.body.parentCampaign?.campaignNumber; - request.body.CampaignDetails.campaignName = - request.body.parentCampaign?.campaignName; - } - } - request.body.CampaignDetails.campaignDetails = { - deliveryRules: request?.body?.CampaignDetails?.deliveryRules || [], - resources: request?.body?.CampaignDetails?.resources || [], - boundaries: request?.body?.CampaignDetails?.boundaries || [], - }; - request.body.CampaignDetails.status = - action == "create" ? campaignStatuses.started : campaignStatuses.drafted; - request.body.CampaignDetails.boundaryCode = getRootBoundaryCode( - request.body?.boundariesCombined - ); - request.body.CampaignDetails.projectType = - request?.body?.CampaignDetails?.projectType || null; - request.body.CampaignDetails.hierarchyType = - request?.body?.CampaignDetails?.hierarchyType || null; - request.body.CampaignDetails.additionalDetails = - request?.body?.CampaignDetails?.additionalDetails || {}; - request.body.CampaignDetails.startDate = - request?.body?.CampaignDetails?.startDate || null; - request.body.CampaignDetails.endDate = - request?.body?.CampaignDetails?.endDate || null; - request.body.CampaignDetails.auditDetails = { - createdBy: request?.body?.RequestInfo?.userInfo?.uuid, - createdTime: Date.now(), - lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, - lastModifiedTime: Date.now(), - }; - if ( - action == "create" && - !request?.body?.CampaignDetails?.projectId && - !firstPersist - ) { - enrichRootProjectId(request.body); - } else { - request.body.CampaignDetails.projectId = null; - } - const topic = firstPersist - ? config?.kafka?.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC - : config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC; - delete request.body.CampaignDetails.codesTargetMapping; - const produceMessage: any = { - CampaignDetails: request?.body?.CampaignDetails, - }; - await produceModifiedMessages(produceMessage, topic); - delete request.body.CampaignDetails.campaignDetails; -} - -function enrichInnerCampaignDetails( - request: any, - updatedInnerCampaignDetails: any -) { - updatedInnerCampaignDetails.resources = - request?.body?.CampaignDetails?.resources || []; - updatedInnerCampaignDetails.deliveryRules = - request?.body?.CampaignDetails?.deliveryRules || []; - updatedInnerCampaignDetails.boundaries = - request?.body?.CampaignDetails?.boundaries || []; -} - -async function enrichAndPersistCampaignForUpdate( - request: any, - firstPersist: boolean = false -) { - const action = request?.body?.CampaignDetails?.action; - const boundaries = request?.body?.boundariesCombined; - const existingCampaignDetails = request?.body?.ExistingCampaignDetails; - callGenerateIfBoundariesOrCampaignTypeDiffer(request); - if (existingCampaignDetails) { - if (areBoundariesSame(existingCampaignDetails?.boundaries, boundaries)) { - updateTargetColumnsIfDeliveryConditionsDifferForSMC(request); - } - } - const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; - var updatedInnerCampaignDetails = {}; - enrichInnerCampaignDetails(request, updatedInnerCampaignDetails); - request.body.CampaignDetails.campaignNumber = - ExistingCampaignDetails?.campaignNumber; - request.body.CampaignDetails.campaignDetails = updatedInnerCampaignDetails; - request.body.CampaignDetails.status = - action == "changeDates" - ? request.body.CampaignDetails.status - : action == "create" - ? campaignStatuses.started - : campaignStatuses.drafted; - const boundaryCode = !request?.body?.CampaignDetails?.projectId - ? getRootBoundaryCode(request.body?.boundariesCombined) - : request?.body?.CampaignDetails?.boundaryCode || - ExistingCampaignDetails?.boundaryCode; - request.body.CampaignDetails.boundaryCode = boundaryCode; - request.body.CampaignDetails.startDate = - request?.body?.CampaignDetails?.startDate || - ExistingCampaignDetails?.startDate || - null; - request.body.CampaignDetails.endDate = - request?.body?.CampaignDetails?.endDate || - ExistingCampaignDetails?.endDate || - null; - request.body.CampaignDetails.projectType = request?.body?.CampaignDetails - ?.projectType - ? request?.body?.CampaignDetails?.projectType - : ExistingCampaignDetails?.projectType; - request.body.CampaignDetails.hierarchyType = request?.body?.CampaignDetails - ?.hierarchyType - ? request?.body?.CampaignDetails?.hierarchyType - : ExistingCampaignDetails?.hierarchyType; - request.body.CampaignDetails.additionalDetails = request?.body - ?.CampaignDetails?.additionalDetails - ? request?.body?.CampaignDetails?.additionalDetails - : ExistingCampaignDetails?.additionalDetails; - request.body.CampaignDetails.auditDetails = { - createdBy: ExistingCampaignDetails?.createdBy, - createdTime: ExistingCampaignDetails?.createdTime, - lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, - lastModifiedTime: Date.now(), - }; - if (action == "create" && !request?.body?.CampaignDetails?.projectId) { - enrichRootProjectId(request.body); - } else { - request.body.CampaignDetails.projectId = - request?.body?.CampaignDetails?.projectId || - ExistingCampaignDetails?.projectId || - null; - } - delete request.body.CampaignDetails.codesTargetMapping; - const producerMessage: any = { - CampaignDetails: request?.body?.CampaignDetails, - }; - await produceModifiedMessages( - producerMessage, - config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC - ); - // delete request.body.ExistingCampaignDetails; - delete request.body.CampaignDetails.campaignDetails; -} - -async function makeParentInactiveOrActive(requestBody: any, active: boolean) { - let parentCampaign = requestBody?.parentCampaign; - parentCampaign.isActive = active; - parentCampaign.campaignDetails = { - deliveryRules: parentCampaign?.deliveryRules || [], - resources: parentCampaign?.resources || [], - boundaries: parentCampaign?.boundaries || [], - }; - parentCampaign.auditDetails.lastModifiedTime = Date.now(); - parentCampaign.auditDetails.lastModifiedBy = - requestBody?.RequestInfo?.userInfo?.uuid; - const produceMessage: any = { - CampaignDetails: parentCampaign, - }; - await produceModifiedMessages( - produceMessage, - config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC - ); + requestBody.CampaignDetails = requestBody?.CampaignDetails || {} + const action = requestBody?.CampaignDetails?.action; + requestBody.CampaignDetails.campaignNumber = requestBody?.CampaignDetails?.campaignNumber || null + requestBody.CampaignDetails.campaignDetails = requestBody?.CampaignDetails?.campaignDetails || { deliveryRules: requestBody?.CampaignDetails?.deliveryRules, resources: requestBody?.CampaignDetails?.resources || [], boundaries: requestBody?.CampaignDetails?.boundaries || [] }; + requestBody.CampaignDetails.status = campaignStatuses?.failed; + requestBody.CampaignDetails.boundaryCode = getRootBoundaryCode(requestBody?.CampaignDetails?.boundaries) || null + requestBody.CampaignDetails.projectType = requestBody?.CampaignDetails?.projectType || null; + requestBody.CampaignDetails.hierarchyType = requestBody?.CampaignDetails?.hierarchyType || null; + requestBody.CampaignDetails.additionalDetails = requestBody?.CampaignDetails?.additionalDetails || {}; + requestBody.CampaignDetails.startDate = requestBody?.CampaignDetails?.startDate || null + requestBody.CampaignDetails.endDate = requestBody?.CampaignDetails?.endDate || null + requestBody.CampaignDetails.auditDetails = { + createdBy: requestBody?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedBy: requestBody?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + } + if (action == "create" && !requestBody?.CampaignDetails?.projectId) { + enrichRootProjectId(requestBody); + } + else if (!requestBody?.CampaignDetails?.projectId) { + requestBody.CampaignDetails.projectId = null + } + requestBody.CampaignDetails.additionalDetails = { + ...requestBody?.CampaignDetails?.additionalDetails, + error: String((error?.message + " : " + error?.description) || error) + } + const topic = config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC + produceModifiedMessages(requestBody, topic); + delete requestBody.CampaignDetails.campaignDetails +} + +async function enrichAndPersistCampaignForCreate(request: any, firstPersist: boolean = false) { + const action = request?.body?.CampaignDetails?.action; + if (firstPersist) { + request.body.CampaignDetails.campaignNumber = await getCampaignNumber(request.body, "CMP-[cy:yyyy-MM-dd]-[SEQ_EG_CMP_ID]", "campaign.number", request?.body?.CampaignDetails?.tenantId); + } + request.body.CampaignDetails.campaignDetails = { deliveryRules: request?.body?.CampaignDetails?.deliveryRules || [], resources: request?.body?.CampaignDetails?.resources || [], boundaries: request?.body?.CampaignDetails?.boundaries || [] }; + request.body.CampaignDetails.status = action == "create" ? campaignStatuses.started : campaignStatuses.drafted; + request.body.CampaignDetails.boundaryCode = getRootBoundaryCode(request.body.CampaignDetails.boundaries) + request.body.CampaignDetails.projectType = request?.body?.CampaignDetails?.projectType || null; + request.body.CampaignDetails.hierarchyType = request?.body?.CampaignDetails?.hierarchyType || null; + request.body.CampaignDetails.additionalDetails = request?.body?.CampaignDetails?.additionalDetails || {}; + request.body.CampaignDetails.startDate = request?.body?.CampaignDetails?.startDate || null + request.body.CampaignDetails.endDate = request?.body?.CampaignDetails?.endDate || null + request.body.CampaignDetails.auditDetails = { + createdBy: request?.body?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + } + if (action == "create" && !request?.body?.CampaignDetails?.projectId && !firstPersist) { + enrichRootProjectId(request.body); + } + else { + request.body.CampaignDetails.projectId = null + } + const topic = firstPersist ? config?.kafka?.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC : config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC + delete request.body.CampaignDetails.codesTargetMapping + produceModifiedMessages(request?.body, topic); + delete request.body.CampaignDetails.campaignDetails +} + +function enrichInnerCampaignDetails(request: any, updatedInnerCampaignDetails: any) { + updatedInnerCampaignDetails.resources = request?.body?.CampaignDetails?.resources || [] + updatedInnerCampaignDetails.deliveryRules = request?.body?.CampaignDetails?.deliveryRules || [] + updatedInnerCampaignDetails.boundaries = request?.body?.CampaignDetails?.boundaries || [] +} + +async function enrichAndPersistCampaignForUpdate(request: any, firstPersist: boolean = false) { + const action = request?.body?.CampaignDetails?.action; + const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + var updatedInnerCampaignDetails = {} + enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) + request.body.CampaignDetails.campaignNumber = ExistingCampaignDetails?.campaignNumber + request.body.CampaignDetails.campaignDetails = updatedInnerCampaignDetails + request.body.CampaignDetails.status = action == "changeDates" ? request.body.CampaignDetails.status : (action == "create" ? campaignStatuses.started : campaignStatuses.drafted); + const boundaryCode = !(request?.body?.CampaignDetails?.projectId) ? getRootBoundaryCode(request.body.CampaignDetails.boundaries) : (request?.body?.CampaignDetails?.boundaryCode || ExistingCampaignDetails?.boundaryCode) + request.body.CampaignDetails.boundaryCode = boundaryCode + request.body.CampaignDetails.startDate = request?.body?.CampaignDetails?.startDate || ExistingCampaignDetails?.startDate || null + request.body.CampaignDetails.endDate = request?.body?.CampaignDetails?.endDate || ExistingCampaignDetails?.endDate || null + request.body.CampaignDetails.projectType = request?.body?.CampaignDetails?.projectType ? request?.body?.CampaignDetails?.projectType : ExistingCampaignDetails?.projectType + request.body.CampaignDetails.hierarchyType = request?.body?.CampaignDetails?.hierarchyType ? request?.body?.CampaignDetails?.hierarchyType : ExistingCampaignDetails?.hierarchyType + request.body.CampaignDetails.additionalDetails = request?.body?.CampaignDetails?.additionalDetails ? request?.body?.CampaignDetails?.additionalDetails : ExistingCampaignDetails?.additionalDetails + request.body.CampaignDetails.auditDetails = { + createdBy: ExistingCampaignDetails?.createdBy, + createdTime: ExistingCampaignDetails?.createdTime, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + } + if (action == "create" && !request?.body?.CampaignDetails?.projectId) { + enrichRootProjectId(request.body); + } + else { + request.body.CampaignDetails.projectId = request?.body?.CampaignDetails?.projectId || ExistingCampaignDetails?.projectId || null + } + delete request.body.CampaignDetails.codesTargetMapping + produceModifiedMessages(request?.body, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC); + delete request.body.ExistingCampaignDetails + delete request.body.CampaignDetails.campaignDetails } function getCreateResourceIds(resources: any[]) { - return resources - .filter( - (resource: any) => - typeof resource.createResourceId === "string" && - resource.createResourceId.trim() !== "" - ) - .map((resource: any) => { - const resourceId = resource.createResourceId; - return resourceId; - }); + return resources + .filter((resource: any) => typeof resource.createResourceId === 'string' && resource.createResourceId.trim() !== '') + .map((resource: any) => { + const resourceId = resource.createResourceId; + return resourceId; + }); +} + +async function persistForCampaignProjectMapping(request: any, createResourceDetailsIds: any, localizationMap?: any) { + if (createResourceDetailsIds && request?.body?.CampaignDetails?.projectId) { + var requestBody: any = { + RequestInfo: request?.body?.RequestInfo, + Campaign: {} + } + requestBody.Campaign.id = request?.body?.CampaignDetails?.id + requestBody.Campaign.hierarchyType = request?.body?.CampaignDetails?.hierarchyType + requestBody.Campaign.tenantId = request?.body?.CampaignDetails?.tenantId + requestBody.Campaign.campaignName = request?.body?.CampaignDetails?.campaignName + requestBody.Campaign.boundaryCode = request?.body?.CampaignDetails?.boundaryCode + requestBody.Campaign.startDate = request?.body?.CampaignDetails?.startDate + requestBody.Campaign.endDate = request?.body?.CampaignDetails?.endDate + requestBody.Campaign.projectType = request?.body?.CampaignDetails?.projectType + requestBody.Campaign.additionalDetails = request?.body?.CampaignDetails?.additionalDetails + requestBody.Campaign.deliveryRules = request?.body?.CampaignDetails?.deliveryRules + requestBody.Campaign.rootProjectId = request?.body?.CampaignDetails?.projectId + requestBody.Campaign.resourceDetailsIds = createResourceDetailsIds + requestBody.CampaignDetails = request?.body?.CampaignDetails + var updatedInnerCampaignDetails = {} + enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) + requestBody.CampaignDetails = request?.body?.CampaignDetails + requestBody.CampaignDetails.campaignDetails = updatedInnerCampaignDetails + requestBody.localizationMap = localizationMap + logger.info("Persisting CampaignProjectMapping..."); + logger.debug(`CampaignProjectMapping: ${getFormattedStringForDebug(requestBody)}`); + produceModifiedMessages(requestBody, config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC); + } } -async function persistForCampaignProjectMapping( - request: any, - createResourceDetailsIds: any, - localizationMap?: any -) { - if (createResourceDetailsIds && request?.body?.CampaignDetails?.projectId) { - var requestBody: any = { - RequestInfo: request?.body?.RequestInfo, - Campaign: {}, - }; - if (request?.body?.ExistingCampaignDetails) { - delete request.body.ExistingCampaignDetails; - } - requestBody.Campaign.id = request?.body?.CampaignDetails?.id; - // requestBody.Campaign.newlyCreatedBoundaryProjectMap = - // request?.body?.newlyCreatedBoundaryProjectMap; - requestBody.Campaign.hierarchyType = - request?.body?.CampaignDetails?.hierarchyType; - requestBody.Campaign.tenantId = request?.body?.CampaignDetails?.tenantId; - requestBody.Campaign.campaignName = - request?.body?.CampaignDetails?.campaignName; - requestBody.Campaign.boundaryCode = - request?.body?.CampaignDetails?.boundaryCode; - requestBody.Campaign.startDate = request?.body?.CampaignDetails?.startDate; - requestBody.Campaign.endDate = request?.body?.CampaignDetails?.endDate; - requestBody.Campaign.projectType = - request?.body?.CampaignDetails?.projectType; - requestBody.Campaign.additionalDetails = - request?.body?.CampaignDetails?.additionalDetails; - requestBody.Campaign.deliveryRules = - request?.body?.CampaignDetails?.deliveryRules; - requestBody.Campaign.rootProjectId = - request?.body?.CampaignDetails?.projectId; - requestBody.Campaign.resourceDetailsIds = createResourceDetailsIds; - requestBody.CampaignDetails = request?.body?.CampaignDetails; - requestBody.parentCampaign = request?.body?.parentCampaign; - var updatedInnerCampaignDetails = {}; - enrichInnerCampaignDetails(request, updatedInnerCampaignDetails); - requestBody.CampaignDetails = request?.body?.CampaignDetails; - requestBody.CampaignDetails.campaignDetails = updatedInnerCampaignDetails; - // requestBody.localizationMap = localizationMap - logger.info("Persisting CampaignProjectMapping..."); - logger.debug( - `CampaignProjectMapping: ${getFormattedStringForDebug(requestBody)}` - ); - await produceModifiedMessages( - requestBody, - config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC - ); - } +function removeBoundariesFromRequest(request: any) { + if (request?.body?.CampaignDetails?.boundaries && Array.isArray(request?.body?.CampaignDetails?.boundaries) && request?.body?.CampaignDetails?.boundaries?.length > 0) { + request.body.CampaignDetails.boundaries = request?.body?.CampaignDetails?.boundaries?.filter((boundary: any) => !boundary?.insertedAfter) + } } -function removeBoundariesFromRequest(request: any) { - const boundaries = request?.body?.CampaignDetails?.boundaries; - if (boundaries && Array.isArray(boundaries) && boundaries?.length > 0) { - request.body.CampaignDetails.boundaries = boundaries?.filter( - (boundary: any) => !boundary?.insertedAfter - ); - } +async function enrichAndPersistProjectCampaignForFirst(request: any, actionInUrl: any, firstPersist: boolean = false, localizationMap?: any) { + removeBoundariesFromRequest(request); + if (actionInUrl == "create") { + await enrichAndPersistCampaignForCreate(request, firstPersist) + } + else if (actionInUrl == "update") { + await enrichAndPersistCampaignForUpdate(request, firstPersist) + } } -async function enrichAndPersistProjectCampaignForFirst( - request: any, - actionInUrl: any, - firstPersist: boolean = false, - localizationMap?: any -) { - removeBoundariesFromRequest(request); - if (actionInUrl == "create") { - await enrichAndPersistCampaignForCreate(request, firstPersist); - } else if (actionInUrl == "update") { - await enrichAndPersistCampaignForUpdate(request, firstPersist); - } - if (request?.body?.parentCampaign?.isActive) { - await makeParentInactiveOrActive(request?.body, false); - } - if (request?.body?.CampaignDetails?.action == "create") { - await createProcessTracks(request.body.CampaignDetails.id); - } -} - -async function enrichAndPersistProjectCampaignRequest( - request: any, - actionInUrl: any, - firstPersist: boolean = false, - localizationMap?: any -) { - var createResourceDetailsIds: any[] = []; - if ( - request?.body?.CampaignDetails?.resources && - Array.isArray(request?.body?.CampaignDetails?.resources) && - request?.body?.CampaignDetails?.resources?.length > 0 && - request?.body?.CampaignDetails?.action == "create" - ) { - createResourceDetailsIds = getCreateResourceIds( - request?.body?.CampaignDetails?.resources - ); - } - // removeBoundariesFromRequest(request); - if (actionInUrl == "create") { - await enrichAndPersistCampaignForCreate(request, firstPersist); - } else if (actionInUrl == "update") { - await enrichAndPersistCampaignForUpdate(request, firstPersist); - } - if (request?.body?.CampaignDetails?.action == "create") { - await persistForCampaignProjectMapping( - request, - createResourceDetailsIds, - localizationMap - ); - } + +async function enrichAndPersistProjectCampaignRequest(request: any, actionInUrl: any, firstPersist: boolean = false, localizationMap?: any) { + var createResourceDetailsIds: any[] = [] + if (request?.body?.CampaignDetails?.resources && Array.isArray(request?.body?.CampaignDetails?.resources) && request?.body?.CampaignDetails?.resources?.length > 0 && request?.body?.CampaignDetails?.action == "create") { + createResourceDetailsIds = getCreateResourceIds(request?.body?.CampaignDetails?.resources); + } + removeBoundariesFromRequest(request); + if (actionInUrl == "create") { + await enrichAndPersistCampaignForCreate(request, firstPersist) + } + else if (actionInUrl == "update") { + await enrichAndPersistCampaignForUpdate(request, firstPersist) + } + if (request?.body?.CampaignDetails?.action == "create") { + await persistForCampaignProjectMapping(request, createResourceDetailsIds, localizationMap); + } } function getChildParentMap(modifiedBoundaryData: any) { - const childParentMap: Map< - { key: string; value: string }, - { key: string; value: string } | null - > = new Map(); - - modifiedBoundaryData.forEach((row: any) => { - for (let j = row.length - 1; j >= 0; j--) { - const child = row[j]; - const parent = j - 1 >= 0 ? row[j - 1] : null; - const childIdentifier = { key: child.key, value: child.value }; // Unique identifier for the child - const parentIdentifier = parent - ? { key: parent.key, value: parent.value } - : null; // Unique identifier for the parent, set to null if parent doesn't exist - - // Check if the mapping already exists in the childParentMap - const existingMapping = Array.from(childParentMap.entries()).find( - ([existingChild, existingParent]) => - _.isEqual(existingChild, childIdentifier) && - _.isEqual(existingParent, parentIdentifier) - ); - - // If the mapping doesn't exist, add it to the childParentMap - if (!existingMapping) { - childParentMap.set(childIdentifier, parentIdentifier); - } - } - }); - return childParentMap; + const childParentMap: Map<{ key: string, value: string }, { key: string, value: string } | null> = new Map(); + + modifiedBoundaryData.forEach((row: any) => { + for (let j = row.length - 1; j >= 0; j--) { + const child = row[j]; + const parent = j - 1 >= 0 ? row[j - 1] : null; + const childIdentifier = { key: child.key, value: child.value }; // Unique identifier for the child + const parentIdentifier = parent ? { key: parent.key, value: parent.value } : null; // Unique identifier for the parent, set to null if parent doesn't exist + + + // Check if the mapping already exists in the childParentMap + const existingMapping = Array.from(childParentMap.entries()).find(([existingChild, existingParent]) => + _.isEqual(existingChild, childIdentifier) && _.isEqual(existingParent, parentIdentifier) + ); + + // If the mapping doesn't exist, add it to the childParentMap + if (!existingMapping) { + childParentMap.set(childIdentifier, parentIdentifier); + } + } + }); + return childParentMap; } + + + + + function getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode: any[]) { - const countMap = new Map<{ key: string; value: string }, number>(); - const mappingMap = new Map<{ key: string; value: string }, string>(); - - withBoundaryCode.forEach((row: any[]) => { - const len = row.length; - if (len >= 3) { - let grandParentFound = false; - const grandParent = row[len - 3]; - if (findMapValue(mappingMap, grandParent)) { - const countMapArray = Array.from(countMap.entries()); - for (const [key, value] of countMapArray) { - if (_.isEqual(key, grandParent)) { - countMap.set(key, value + 1); - grandParentFound = true; - break; - } - } - if (grandParentFound == false) { - countMap.set(grandParent, 1); + const countMap = new Map<{ key: string, value: string }, number>(); + const mappingMap = new Map<{ key: string, value: string }, string>(); + + withBoundaryCode.forEach((row: any[]) => { + const len = row.length; + if (len >= 3) { + let grandParentFound = false; + const grandParent = row[len - 3]; + if (findMapValue(mappingMap, grandParent)) { + const countMapArray = Array.from(countMap.entries()); + for (const [key, value] of countMapArray) { + if (_.isEqual(key, grandParent)) { + countMap.set(key, value + 1); + grandParentFound = true; + break; + } + } + if (grandParentFound == false) { + countMap.set(grandParent, 1); + } + } } - } - } - mappingMap.set(row[len - 2], row[len - 1].value); - }); - return { mappingMap, countMap }; + mappingMap.set(row[len - 2], row[len - 1].value); + }); + return { mappingMap, countMap }; } -function addBoundaryCodeToData( - withBoundaryCode: any[], - withoutBoundaryCode: any[], - boundaryMap: Map -) { - const boundaryDataWithBoundaryCode = withBoundaryCode; - const modifiedBoundaryDataWithBoundaryCode = boundaryDataWithBoundaryCode.map( - (array) => { - return array.map((obj: any) => { - if (obj.key === "Boundary Code") { - return obj.value; - } else { - return obj; - } - }); - } - ); - const boundaryDataForWithoutBoundaryCode = withoutBoundaryCode.map( - (row: any[]) => { - const boundaryName = row[row.length - 1]; // Get the last element of the row - const boundaryCode = findMapValue(boundaryMap, boundaryName); // Fetch corresponding boundary code from map - return [...row, boundaryCode]; // Append boundary code to the row and return updated row - } - ); - const boundaryDataForSheet = [ - ...modifiedBoundaryDataWithBoundaryCode, - ...boundaryDataForWithoutBoundaryCode, - ]; - return boundaryDataForSheet; -} +function addBoundaryCodeToData(withBoundaryCode: any[], withoutBoundaryCode: any[], boundaryMap: Map) { + const boundaryDataWithBoundaryCode = withBoundaryCode; + const modifiedBoundaryDataWithBoundaryCode = boundaryDataWithBoundaryCode.map((array) => { + return array.map((obj: any) => { + if (obj.key === 'Boundary Code') { + return obj.value; + } else { + return obj; + } + }); + }); -function prepareDataForExcel( - boundaryDataForSheet: any, - hierarchy: any[], - boundaryMap: any -) { - const data = boundaryDataForSheet.map((boundary: any[]) => { - const boundaryCode = boundary.pop(); - const boundaryValues = boundary.map((obj) => obj.value); - const rowData = boundaryValues.concat( - Array(Math.max(0, hierarchy.length - boundary.length)).fill("") - ); - const boundaryCodeIndex = hierarchy.length; - rowData[boundaryCodeIndex] = boundaryCode; - return rowData; - }); - return data; + const boundaryDataForWithoutBoundaryCode = withoutBoundaryCode.map((row: any[]) => { + const boundaryName = row[row.length - 1]; // Get the last element of the row + const boundaryCode = findMapValue(boundaryMap, boundaryName); // Fetch corresponding boundary code from map + return [...row, boundaryCode]; // Append boundary code to the row and return updated row + }); + const boundaryDataForSheet = [...modifiedBoundaryDataWithBoundaryCode, ...boundaryDataForWithoutBoundaryCode]; + return boundaryDataForSheet; +} + +function prepareDataForExcel(boundaryDataForSheet: any, hierarchy: any[], boundaryMap: any) { + const data = boundaryDataForSheet.map((boundary: any[]) => { + const boundaryCode = boundary.pop(); + const boundaryValues = boundary.map(obj => obj.value); + const rowData = boundaryValues.concat(Array(Math.max(0, hierarchy.length - boundary.length)).fill('')); + const boundaryCodeIndex = hierarchy.length; + rowData[boundaryCodeIndex] = boundaryCode; + return rowData; + }); + return data; } function extractCodesFromBoundaryRelationshipResponse(boundaries: any[]): any { - const codes = new Set(); - for (const boundary of boundaries) { - codes.add(boundary.code); // Add code to the Set - if (boundary.children && boundary.children.length > 0) { - const childCodes = extractCodesFromBoundaryRelationshipResponse( - boundary.children - ); // Recursively get child codes - childCodes.forEach((code: any) => codes.add(code)); // Add child codes to the Set - } - } - return codes; -} - -async function getTotalCount(campaignDetails: any) { - const { tenantId, pagination, ids, ...searchFields } = campaignDetails; - let conditions = []; - let values = [tenantId]; - let index = 2; - const campaignsIncludeDates = searchFields?.campaignsIncludeDates; - - for (const field in searchFields) { - if (searchFields[field] !== undefined && field != "campaignsIncludeDates") { - if (field === "startDate") { - const startDateSign = campaignsIncludeDates ? "<=" : ">="; - conditions.push(`startDate ${startDateSign} $${index}`); - values.push(searchFields[field]); - index++; - } else if (field === "endDate") { - const endDateSign = campaignsIncludeDates ? ">=" : "<="; - conditions.push(`endDate ${endDateSign} $${index}`); - values.push(searchFields[field]); - index++; - } else if (field === "campaignName") { - conditions.push(`${field} ILIKE '%' || $${index} || '%'`); - values.push(searchFields[field]); - index++; - } else if (field != "status") { - conditions.push(`${field} = $${index}`); - values.push(searchFields[field]); - index++; - } - } - } - - let query = ` + const codes = new Set(); + for (const boundary of boundaries) { + codes.add(boundary.code); // Add code to the Set + if (boundary.children && boundary.children.length > 0) { + const childCodes = extractCodesFromBoundaryRelationshipResponse(boundary.children); // Recursively get child codes + childCodes.forEach((code: any) => codes.add(code)); // Add child codes to the Set + } + } + return codes; +} + + +async function getTotalCount(request: any) { + const CampaignDetails = request.body.CampaignDetails; + const { tenantId, pagination, ids, ...searchFields } = CampaignDetails; + let conditions = []; + let values = [tenantId]; + let index = 2; + const campaignsIncludeDates = searchFields?.campaignsIncludeDates + + for (const field in searchFields) { + if (searchFields[field] !== undefined && field != 'campaignsIncludeDates') { + if (field === 'startDate') { + const startDateSign = campaignsIncludeDates ? '<=' : '>='; + conditions.push(`startDate ${startDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === 'endDate') { + const endDateSign = campaignsIncludeDates ? '>=' : '<='; + conditions.push(`endDate ${endDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === 'campaignName') { + conditions.push(`${field} ILIKE '%' || $${index} || '%'`); + values.push(searchFields[field]); + index++; + } else if (field != 'status') { + conditions.push(`${field} = $${index}`); + values.push(searchFields[field]); + index++; + } + } + } + + let query = ` SELECT count(*) FROM ${config?.DB_CONFIG.DB_CAMPAIGN_DETAILS_TABLE_NAME} WHERE tenantId = $1 `; - if (ids && ids.length > 0) { - const idParams = ids.map((id: any, i: any) => `$${index + i}`); - query += ` AND id IN (${idParams.join(", ")})`; - values.push(...ids); - index = index + ids.length; - } else { - // If no IDs are provided, filter by isActive = true - query += ` AND isActive = true`; - } - var status = searchFields?.status; - if (status) { - if (typeof status === "string") { - status = [status]; // Convert string to array - } - const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter - query += ` AND status IN (${statusParams.join(", ")})`; - values.push(...status); - } - - if (conditions.length > 0) { - query += ` AND ${conditions.join(" AND ")}`; - } - const queryResult = await executeQuery(query, values); - const totalCount = parseInt(queryResult.rows[0].count, 10); - return totalCount; -} - -async function searchProjectCampaignResourcData(campaignDetails: any) { - // const CampaignDetails = request.body.CampaignDetails; - const { tenantId, pagination, ids, ...searchFields } = campaignDetails; - const queryData = buildSearchQuery(tenantId, pagination, ids, searchFields); - const totalCount = await getTotalCount(campaignDetails); - const responseData: any[] = await executeSearchQuery( - queryData.query, - queryData.values - ); - // TODO @ashish check the below code looks like duplicate - for (const data of responseData) { - data.resources = data?.campaignDetails?.resources; - data.boundaries = data?.campaignDetails?.boundaries; - data.deliveryRules = data?.campaignDetails?.deliveryRules; - delete data.campaignDetails; - data.auditDetails = { - createdBy: data?.createdBy, - lastModifiedBy: data?.lastModifiedBy, - createdTime: data?.createdTime, - lastModifiedTime: data?.lastModifiedTime, - }; - delete data.createdBy; - delete data.lastModifiedBy; - delete data.createdTime; - delete data.lastModifiedTime; - } - return { responseData, totalCount }; -} - -function buildSearchQuery( - tenantId: string, - pagination: any, - ids: string[], - searchFields: any -): { query: string; values: any[] } { - let conditions = []; - let values = [tenantId]; - let index = 2; - const campaignsIncludeDates = searchFields?.campaignsIncludeDates; - - for (const field in searchFields) { - if (searchFields[field] !== undefined && field != "campaignsIncludeDates") { - if (field === "startDate") { - const startDateSign = campaignsIncludeDates ? "<=" : ">="; - conditions.push(`startDate ${startDateSign} $${index}`); - values.push(searchFields[field]); - index++; - } else if (field === "endDate") { - const endDateSign = campaignsIncludeDates ? ">=" : "<="; - conditions.push(`endDate ${endDateSign} $${index}`); - values.push(searchFields[field]); - index++; - } else if (field === "campaignName") { - conditions.push(`${field} ILIKE '%' || $${index} || '%'`); - values.push(searchFields[field]); - index++; - } else if (field != "status") { - conditions.push(`${field} = $${index}`); - values.push(searchFields[field]); - index++; - } - } - } - - let query = ` + if (ids && ids.length > 0) { + const idParams = ids.map((id: any, i: any) => `$${index + i}`); + query += ` AND id IN (${idParams.join(', ')})`; + values.push(...ids); + index = index + ids.length; + } + var status = searchFields?.status; + if (status) { + if (typeof status === 'string') { + status = [status]; // Convert string to array + } + const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter + query += ` AND status IN (${statusParams.join(', ')})`; + values.push(...status); + } + + if (conditions.length > 0) { + query += ` AND ${conditions.join(' AND ')}`; + } + const queryResult = await executeQuery(query, values); + const totalCount = parseInt(queryResult.rows[0].count, 10); + request.body.totalCount = totalCount; +} + + + + +async function searchProjectCampaignResourcData(request: any) { + const CampaignDetails = request.body.CampaignDetails; + const { tenantId, pagination, ids, ...searchFields } = CampaignDetails; + const queryData = buildSearchQuery(tenantId, pagination, ids, searchFields); + await getTotalCount(request) + const responseData: any[] = await executeSearchQuery(queryData.query, queryData.values); + // TODO @ashish check the below code looks like duplicate + for (const data of responseData) { + data.resources = data?.campaignDetails?.resources + data.boundaries = data?.campaignDetails?.boundaries + data.deliveryRules = data?.campaignDetails?.deliveryRules; + delete data.campaignDetails; + data.auditDetails = { + createdBy: data?.createdBy, + lastModifiedBy: data?.lastModifiedBy, + createdTime: data?.createdTime, + lastModifiedTime: data?.lastModifiedTime + } + delete data.createdBy; + delete data.lastModifiedBy; + delete data.createdTime; + delete data.lastModifiedTime; + } + request.body.CampaignDetails = responseData; +} + +function buildSearchQuery(tenantId: string, pagination: any, ids: string[], searchFields: any): { query: string, values: any[] } { + let conditions = []; + let values = [tenantId]; + let index = 2; + const campaignsIncludeDates = searchFields?.campaignsIncludeDates + + for (const field in searchFields) { + if (searchFields[field] !== undefined && field != 'campaignsIncludeDates') { + if (field === 'startDate') { + const startDateSign = campaignsIncludeDates ? '<=' : '>='; + conditions.push(`startDate ${startDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === 'endDate') { + const endDateSign = campaignsIncludeDates ? '>=' : '<='; + conditions.push(`endDate ${endDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === 'campaignName') { + conditions.push(`${field} ILIKE '%' || $${index} || '%'`); + values.push(searchFields[field]); + index++; + } else if (field != 'status') { + conditions.push(`${field} = $${index}`); + values.push(searchFields[field]); + index++; + } + } + } + + let query = ` SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_DETAILS_TABLE_NAME} WHERE tenantId = $1 `; - if (ids && ids.length > 0) { - const idParams = ids.map((id: any, i: any) => `$${index + i}`); - query += ` AND id IN (${idParams.join(", ")})`; - values.push(...ids); - index = index + ids.length; - } else { - // If no IDs are provided, filter by isActive = true - query += ` AND isActive = true`; - } + if (ids && ids.length > 0) { + const idParams = ids.map((id: any, i: any) => `$${index + i}`); + query += ` AND id IN (${idParams.join(', ')})`; + values.push(...ids); + index = index + ids.length; + } - var status = searchFields?.status; - if (status) { - if (typeof status === "string") { - status = [status]; // Convert string to array + var status = searchFields?.status; + if (status) { + if (typeof status === 'string') { + status = [status]; // Convert string to array + } + const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter + query += ` AND status IN (${statusParams.join(', ')})`; + values.push(...status); } - const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter - query += ` AND status IN (${statusParams.join(", ")})`; - values.push(...status); - } - if (conditions.length > 0) { - query += ` AND ${conditions.join(" AND ")}`; - } + if (conditions.length > 0) { + query += ` AND ${conditions.join(' AND ')}`; + } - if (pagination) { - query += "\n"; + if (pagination) { + query += '\n'; - if (pagination.sortBy) { - query += `ORDER BY ${pagination.sortBy}`; - if (pagination.sortOrder) { - query += ` ${pagination.sortOrder.toUpperCase()}`; - } - query += "\n"; - } + if (pagination.sortBy) { + query += `ORDER BY ${pagination.sortBy}`; + if (pagination.sortOrder) { + query += ` ${pagination.sortOrder.toUpperCase()}`; + } + query += '\n'; + } - if (pagination.limit !== undefined) { - query += `LIMIT ${pagination.limit}`; - if (pagination.offset !== undefined) { - query += ` OFFSET ${pagination.offset}`; - } - query += "\n"; + if (pagination.limit !== undefined) { + query += `LIMIT ${pagination.limit}`; + if (pagination.offset !== undefined) { + query += ` OFFSET ${pagination.offset}`; + } + query += '\n'; + } } - } - return { query, values }; + return { query, values }; } + + async function executeSearchQuery(query: string, values: any[]) { - const queryResult = await executeQuery(query, values); - return campaignDetailsTransformer(queryResult?.rows); + const queryResult = await executeQuery(query, values); + return campaignDetailsTransformer(queryResult?.rows); } async function processDataSearchRequest(request: any) { - const { SearchCriteria } = request.body; - const query = buildWhereClauseForDataSearch(SearchCriteria); - const queryResult = await executeQuery(query.query, query.values); - request.body.ResourceDetails = genericResourceTransformer(queryResult?.rows); -} - -function buildWhereClauseForDataSearch(SearchCriteria: any): { - query: string; - values: any[]; -} { - const { id, tenantId, type, status, hierarchyType } = SearchCriteria; - let conditions = []; - let values = []; - - // Check for id - if (id && id.length > 0) { - conditions.push(`id = ANY($${values.length + 1})`); - values.push(id); - } - - // Check for tenantId - if (tenantId) { - conditions.push(`tenantId = $${values.length + 1}`); - values.push(tenantId); - } - - // Check for type - if (type) { - conditions.push(`type = $${values.length + 1}`); - values.push(type); - } - - // Check for status - if (status) { - conditions.push(`status = $${values.length + 1}`); - values.push(status); - } - - // Check for hierarchyType - if (hierarchyType) { - conditions.push(`hierarchyType = $${values.length + 1}`); - values.push(hierarchyType); - } - - // Build the WHERE clause - const whereClause = - conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : ""; - - // Return the query and values array - return { - query: ` - SELECT * - FROM ${config?.DB_CONFIG.DB_RESOURCE_DETAILS_TABLE_NAME} - ${whereClause};`, - values, - }; + const { SearchCriteria } = request.body; + const query = buildWhereClauseForDataSearch(SearchCriteria); + const queryResult = await executeQuery(query.query, query.values); + request.body.ResourceDetails = genericResourceTransformer(queryResult?.rows);; } -function mapBoundariesParent(boundaryResponse: any, request: any, parent: any) { - if (!boundaryResponse) return; +function buildWhereClauseForDataSearch(SearchCriteria: any): { query: string; values: any[] } { + const { id, tenantId, type, status } = SearchCriteria; + let conditions = []; + let values = []; - request.body.boundaryProjectMapping[boundaryResponse.code] = { - parent: parent || null, - projectId: null, - }; - if ( - boundaryResponse?.children && - Array.isArray(boundaryResponse?.children) && - boundaryResponse?.children?.length > 0 - ) { - for (const child of boundaryResponse.children) { - mapBoundariesParent(child, request, boundaryResponse.code); + if (id && id.length > 0) { + conditions.push(`id = ANY($${values.length + 1})`); + values.push(id); } - } -} -function mapTargets(boundaryResponses: any, codesTargetMapping: any) { - if (!boundaryResponses || !codesTargetMapping) return; - - for (const boundaryResponse of boundaryResponses) { - const mapBoundary = (boundary: any) => { - if (!boundary.children || boundary.children.length === 0) { - const targetValue = codesTargetMapping[boundary.code]; - return targetValue ? targetValue : 0; - } - - let totalTargetValue = 0; - for (const child of boundary.children) { - const childTargetValue = mapBoundary(child); - totalTargetValue += childTargetValue; - } - codesTargetMapping[boundary.code] = totalTargetValue; - return totalTargetValue; + if (tenantId) { + conditions.push(`tenantId = $${values.length + 1}`); + values.push(tenantId); + } + + if (type) { + conditions.push(`type = $${values.length + 1}`); + values.push(type); + } + + if (status) { + conditions.push(`status = $${values.length + 1}`); + values.push(status); + } + + const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''; + + return { + query: ` + SELECT * + FROM ${config?.DB_CONFIG.DB_RESOURCE_DETAILS_TABLE_NAME} + ${whereClause};`, values }; - mapBoundary(boundaryResponse); - } } -async function processBoundary( - boundaryResponse: any, - boundaries: any, - includeAllChildren: any, - boundaryCodes: any, - boundaryChildren: any -) { - if (!boundaryResponse) return; - if (!boundaryCodes.has(boundaryResponse.code)) { - boundaries.push({ - code: boundaryResponse?.code, - type: boundaryResponse?.boundaryType, - insertedAfter: true, - }); - boundaryCodes.add(boundaryResponse?.code); - } - if ( - includeAllChildren && - boundaryResponse?.children && - Array.isArray(boundaryResponse?.children) && - boundaryResponse?.children?.length > 0 - ) { - for (const child of boundaryResponse.children) { - processBoundary(child, boundaries, true, boundaryCodes, boundaryChildren); - } - } else if ( - boundaryResponse?.children && - Array.isArray(boundaryResponse?.children) && - boundaryResponse?.children?.length > 0 - ) { - for (const child of boundaryResponse.children) { - if (boundaryCodes.has(child.code) && boundaryChildren[child.code]) { - processBoundary( - child, - boundaries, - true, - boundaryCodes, - boundaryChildren - ); - } else if (boundaryCodes.has(child.code)) { - processBoundary( - child, - boundaries, - false, - boundaryCodes, - boundaryChildren - ); - } - } - } -} - -async function addBoundaries( - request: any, - boundaryResponse: any, - boundaryChildren: any -) { - var boundaries = request?.body?.boundariesCombined; - var boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code)); - await processBoundary( - boundaryResponse, - boundaries, - boundaryChildren[boundaryResponse?.code], - boundaryCodes, - boundaryChildren - ); - request.body.boundariesCombined = boundaries; +function mapBoundariesParent(boundaryResponse: any, request: any, parent: any) { + if (!boundaryResponse) return; + request.body.boundaryProjectMapping[boundaryResponse.code] = { + parent: parent || null, + projectId: null + } + if (boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { + for (const child of boundaryResponse.children) { + mapBoundariesParent(child, request, boundaryResponse.code); + } + } } -async function addBoundariesForData(request: any, CampaignDetails: any) { - // var { boundaries } = CampaignDetails; - var boundaries = await getBoundariesFromCampaignSearchResponse( - request, - CampaignDetails - ); - const rootBoundary = getRootBoundaryCode(boundaries); - if (rootBoundary) { - const params = { - tenantId: request?.body?.ResourceDetails?.tenantId, - codes: rootBoundary, - hierarchyType: request?.body?.ResourceDetails?.hierarchyType, - includeChildren: true, - }; - const header = { - ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId - }${params.codes || ""}${params?.includeChildren || ""}`, - }; - const boundaryResponse = await httpRequest( - config.host.boundaryHost + config.paths.boundaryRelationship, - request.body, - params, - undefined, - undefined, - header - ); - if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { - var boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { - acc[boundary.code] = boundary?.includeAllChildren; - return acc; - }, {}); - var boundaryCodes = new Set( - boundaries.map((boundary: any) => boundary.code) - ); - await processBoundary( - boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], - boundaries, - boundaryChildren[ - boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]?.code - ], - boundaryCodes, - boundaryChildren - ); - CampaignDetails.boundaries = boundaries; - } else { - throwError( - "COMMON", - 500, - "INTERNAL_SERVER_ERROR", - "Some internal server error occured during boundary validation." - ); - } - } else { - throwError( - "COMMON", - 500, - "INTERNAL_SERVER_ERROR", - "There is no root boundary for this campaign." - ); - } +function mapTargets(boundaryResponses: any, codesTargetMapping: any) { + if (!boundaryResponses || !codesTargetMapping) return; + + for (const boundaryResponse of boundaryResponses) { + const mapBoundary = (boundary: any) => { + if (!boundary.children || boundary.children.length === 0) { + const targetValue = codesTargetMapping[boundary.code]; + return targetValue ? targetValue : 0; + } + + let totalTargetValue = 0; + for (const child of boundary.children) { + const childTargetValue = mapBoundary(child); + totalTargetValue += childTargetValue; + } + codesTargetMapping[boundary.code] = totalTargetValue; + return totalTargetValue; + }; + mapBoundary(boundaryResponse); + } } -function reorderBoundariesWithParentFirst( - boundaries: any[], - boundaryProjectMapping: any -) { - const startTime = Date.now(); - - const boundaryGraph = new Map(); - const inDegree = new Map(); - - logger.info(`Started processing ${boundaries.length} boundaries...`); - - // Step 1: Build the graph and calculate in-degrees - boundaries.forEach((boundary) => { - const code = boundary.code; - boundaryGraph.set(code, []); - inDegree.set(code, 0); // Initialize in-degree for each boundary - }); - - boundaries.forEach((boundary) => { - const code = boundary.code; - const parentCode = boundaryProjectMapping[code]?.parent; - - if (parentCode) { - boundaryGraph.get(parentCode).push(code); // Parent points to child - inDegree.set(code, inDegree.get(code) + 1); // Increment in-degree of child - } - }); - - const graphConstructionTime = Date.now(); - logger.info( - `Graph construction completed. Time taken: ${( - (graphConstructionTime - startTime) / 1000 - ).toFixed(2)} seconds.` - ); - - // Step 2: Perform topological sort using Kahn's Algorithm - const queue: any = []; - const sortedBoundaries = []; - - // Enqueue nodes with 0 in-degree - boundaries.forEach((boundary) => { - if (inDegree.get(boundary.code) === 0) { - queue.push(boundary); - } - }); - - let nodesProcessed = 0; - while (queue.length > 0) { - const currentBoundary = queue.shift(); - sortedBoundaries.push(currentBoundary); - nodesProcessed++; - - // Log progress periodically - if (nodesProcessed % 500 === 0) { - const elapsed = (Date.now() - startTime) / 1000; - const avgTimePerBoundary = elapsed / nodesProcessed; - const estimatedRemaining = avgTimePerBoundary * (boundaries.length - nodesProcessed); - logger.info( - `Processed ${nodesProcessed} boundaries. Elapsed: ${elapsed.toFixed( - 2 - )} seconds. Estimated time remaining: ${estimatedRemaining.toFixed(2)} seconds.` - ); - } - - const children = boundaryGraph.get(currentBoundary.code) || []; - children.forEach((childCode: any) => { - inDegree.set(childCode, inDegree.get(childCode) - 1); - if (inDegree.get(childCode) === 0) { - queue.push( - boundaries.find((boundary) => boundary.code === childCode) - ); - } - }); - } - // Check for cycles (remaining nodes with non-zero in-degree) - if (sortedBoundaries.length !== boundaries.length) { - throw new Error( - "Cycle detected in the boundary-parent relationships. Reordering failed." - ); - } +async function processBoundary(boundaryResponse: any, boundaries: any, includeAllChildren: any, boundaryCodes: any, boundaryChildren: any) { + if (!boundaryResponse) return; + if (!boundaryCodes.has(boundaryResponse.code)) { + boundaries.push({ code: boundaryResponse?.code, type: boundaryResponse?.boundaryType, insertedAfter: true }); + boundaryCodes.add(boundaryResponse?.code); + } + if (includeAllChildren && boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { + for (const child of boundaryResponse.children) { + processBoundary(child, boundaries, true, boundaryCodes, boundaryChildren); + } + } + else if (boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { + for (const child of boundaryResponse.children) { + if (boundaryCodes.has(child.code) && boundaryChildren[child.code]) { + processBoundary(child, boundaries, true, boundaryCodes, boundaryChildren); + } + else if (boundaryCodes.has(child.code)) { + processBoundary(child, boundaries, false, boundaryCodes, boundaryChildren); + } + } + } +} - const endTime = Date.now(); - logger.info( - `Reordering completed. Processed ${boundaries.length} boundaries in ${( - (endTime - startTime) / 1000 - ).toFixed(2)} seconds.` - ); +async function addBoundaries(request: any, boundaryResponse: any, boundaryChildren: any) { + var { boundaries } = request?.body?.CampaignDetails; + var boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code)); + await processBoundary(boundaryResponse, boundaries, boundaryChildren[boundaryResponse?.code], boundaryCodes, boundaryChildren); + request.body.CampaignDetails.boundaries = boundaries +} - return sortedBoundaries; +async function addBoundariesForData(request: any, CampaignDetails: any) { + var { boundaries } = CampaignDetails; + const rootBoundary = getRootBoundaryCode(boundaries) + if (rootBoundary) { + const params = { + tenantId: request?.body?.ResourceDetails?.tenantId, + codes: rootBoundary, + hierarchyType: request?.body?.ResourceDetails?.hierarchyType, + includeChildren: true + } + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + } + const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, params, undefined, undefined, header); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + var boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { + acc[boundary.code] = boundary?.includeAllChildren; + return acc; + }, {}); + var boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code)); + await processBoundary(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], boundaries, boundaryChildren[boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]?.code], boundaryCodes, boundaryChildren); + CampaignDetails.boundaries = boundaries + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Some internal server error occured during boundary validation."); + } + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "There is no root boundary for this campaign."); + } } -async function reorderBoundariesOfDataAndValidate( - request: any, - localizationMap?: any -) { - if (request?.body?.ResourceDetails?.campaignId) { - // const searchBody = { - // RequestInfo: request?.body?.RequestInfo, - const CampaignDetails = { - ids: [request?.body?.ResourceDetails?.campaignId], - tenantId: request?.body?.ResourceDetails?.tenantId, - } - // }; - // const req: any = replicateRequest(request, searchBody); - const response = await searchProjectTypeCampaignService(CampaignDetails); - if (response?.CampaignDetails?.[0]) { - const CampaignDetails = response?.CampaignDetails?.[0]; - await addBoundariesForData(request, CampaignDetails); - logger.debug( - "Boundaries after addition " + - getFormattedStringForDebug(CampaignDetails?.boundaries) - ); - await validateBoundaryOfResouces( - CampaignDetails, - request, - localizationMap - ); - } else { - throwError( - "CAMPAIGN", - 400, - "CAMPAIGN_NOT_FOUND", - "Campaign not found while Validating sheet boundaries" - ); +function reorderBoundariesWithParentFirst(reorderedBoundaries: any[], boundaryProjectMapping: any) { + // Function to get the index of a boundary in the original boundaries array + function getIndex(code: any, boundaries: any[]) { + return reorderedBoundaries.findIndex((boundary: any) => boundary.code === code); + } + // Reorder boundaries so that parents come first + for (let i = 0; i < 2 * (reorderedBoundaries?.length); i++) { + for (const boundary of reorderedBoundaries) { + const parentCode = boundaryProjectMapping[boundary.code]?.parent; + if (parentCode) { + const parentIndex = getIndex(parentCode, reorderedBoundaries); + const boundaryIndex = getIndex(boundary.code, reorderedBoundaries); + + if (parentIndex !== -1 && boundaryIndex !== -1 && parentIndex > boundaryIndex) { + reorderedBoundaries.splice(parentIndex + 1, 0, reorderedBoundaries.splice(boundaryIndex, 1)[0]); + break; + } + } + } + } +} + +async function reorderBoundariesOfDataAndValidate(request: any, localizationMap?: any) { + if (request?.body?.ResourceDetails?.campaignId) { + const searchBody = { + RequestInfo: request?.body?.RequestInfo, + CampaignDetails: { + ids: [request?.body?.ResourceDetails?.campaignId], + tenantId: request?.body?.ResourceDetails?.tenantId + } + } + const req: any = replicateRequest(request, searchBody) + const response = await searchProjectTypeCampaignService(req) + if (response?.CampaignDetails?.[0]) { + const CampaignDetails = response?.CampaignDetails?.[0] + await addBoundariesForData(request, CampaignDetails) + logger.debug("Boundaries after addition " + getFormattedStringForDebug(CampaignDetails?.boundaries)); + await validateBoundaryOfResouces(CampaignDetails, request, localizationMap) + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while Validating sheet boundaries"); + } } - } } async function reorderBoundaries(request: any, localizationMap?: any) { - // var { boundaries } = request?.body?.CampaignDetails; - var boundaries = request?.body?.boundariesCombined; - const rootBoundary = getRootBoundaryCode(boundaries); - request.body.boundaryProjectMapping = {}; - if (rootBoundary) { - const params = { - tenantId: request?.body?.CampaignDetails?.tenantId, - codes: rootBoundary, - hierarchyType: request?.body?.CampaignDetails?.hierarchyType, - includeChildren: true, - }; - const header = { - ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId - }${params.codes || ""}${params?.includeChildren || ""}`, - }; - const boundaryResponse = await httpRequest( - config.host.boundaryHost + config.paths.boundaryRelationship, - request.body, - params, - undefined, - undefined, - header - ); - if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { - const codesTargetMapping = await getCodesTarget(request, localizationMap); - if (codesTargetMapping) { - mapTargets( - boundaryResponse?.TenantBoundary?.[0]?.boundary, - codesTargetMapping - ); - request.body.CampaignDetails.codesTargetMapping = codesTargetMapping; - logger.debug( - "codesTargetMapping mapping :: " + - getFormattedStringForDebug(codesTargetMapping) - ); - } - mapBoundariesParent( - boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], - request, - null - ); - var boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { - acc[boundary.code] = boundary?.includeAllChildren; - return acc; - }, {}); - await addBoundaries( - request, - boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], - boundaryChildren - ); - } else { - throwError( - "COMMON", - 500, - "INTERNAL_SERVER_ERROR", - "Some internal server error occured during boundary validation." - ); - } - } else { - throwError( - "COMMON", - 500, - "INTERNAL_SERVER_ERROR", - "There is no root boundary for this campaign." - ); - } - logger.info("Boundaries for campaign creation in received"); - logger.debug( - "Boundaries after addition " + - getFormattedStringForDebug(request?.body?.boundariesCombined) - ); - const start = Date.now(); - const sortedBoundaries = reorderBoundariesWithParentFirst( - request?.body?.boundariesCombined, - request?.body?.boundaryProjectMapping - ); - request.body.boundariesCombined = sortedBoundaries; - const end = Date.now(); - logger.info(`Execution time: ${(end - start) / 1000} seconds`); - logger.info("Reordered the Boundaries for mapping"); - logger.debug( - "Reordered Boundaries " + - getFormattedStringForDebug(request?.body?.boundariesCombined) - ); - return request.body.boundariesCombined; + var { boundaries } = request?.body?.CampaignDetails; + const rootBoundary = getRootBoundaryCode(boundaries) + request.body.boundaryProjectMapping = {} + if (rootBoundary) { + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + codes: rootBoundary, + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + includeChildren: true + } + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + } + const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, params, undefined, undefined, header); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + const codesTargetMapping = await getCodesTarget(request, localizationMap) + mapTargets(boundaryResponse?.TenantBoundary?.[0]?.boundary, codesTargetMapping) + request.body.CampaignDetails.codesTargetMapping = codesTargetMapping + logger.debug("codesTargetMapping mapping :: " + getFormattedStringForDebug(codesTargetMapping)); + mapBoundariesParent(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], request, null) + var boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { + acc[boundary.code] = boundary?.includeAllChildren; + return acc; + }, {}); + await addBoundaries(request, boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], boundaryChildren) + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Some internal server error occured during boundary validation."); + } + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "There is no root boundary for this campaign."); + } + logger.info("Boundaries for campaign creation in received") + logger.debug("Boundaries after addition " + getFormattedStringForDebug(request?.body?.CampaignDetails?.boundaries)); + reorderBoundariesWithParentFirst(request?.body?.CampaignDetails?.boundaries, request?.body?.boundaryProjectMapping) + logger.info("Reordered the Boundaries for mapping"); + logger.debug("Reordered Boundaries " + getFormattedStringForDebug(request?.body?.CampaignDetails?.boundaries)); } function convertToProjectsArray(Projects: any, currentArray: any = []) { - for (const project of Projects) { - const descendants = project?.descendants; - delete project?.descendants; - currentArray.push(project); - if (descendants && Array.isArray(descendants) && descendants?.length > 0) { - convertToProjectsArray(descendants, currentArray); + for (const project of Projects) { + const descendants = project?.descendants + delete project?.descendants + currentArray.push(project); + if (descendants && Array.isArray(descendants) && descendants?.length > 0) { + convertToProjectsArray(descendants, currentArray) + } } - } - return currentArray; + return currentArray; } async function getRelatedProjects(request: any) { - const { projectId, tenantId } = request?.body?.CampaignDetails; - const projectSearchBody = { - RequestInfo: request?.body?.RequestInfo, - Projects: [ - { - id: projectId, + const { projectId, tenantId } = request?.body?.CampaignDetails; + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo, + Projects: [ + { + id: projectId, + tenantId: tenantId + } + ] + } + const projectSearchParams = { tenantId: tenantId, - }, - ], - }; - const projectSearchParams = { - tenantId: tenantId, - offset: 0, - limit: 1, - includeDescendants: true, - }; - logger.info("Project search params " + JSON.stringify(projectSearchParams)); - const projectSearchResponse = await httpRequest( - config?.host?.projectHost + config?.paths?.projectSearch, - projectSearchBody, - projectSearchParams - ); - if ( - projectSearchResponse?.Project && - Array.isArray(projectSearchResponse?.Project) && - projectSearchResponse?.Project?.length > 0 - ) { - return convertToProjectsArray(projectSearchResponse?.Project); - } else { - throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR"); - return []; - } + offset: 0, + limit: 1, + includeDescendants: true + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + const projectSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectSearch, projectSearchBody, projectSearchParams); + if (projectSearchResponse?.Project && Array.isArray(projectSearchResponse?.Project) && projectSearchResponse?.Project?.length > 0) { + return convertToProjectsArray(projectSearchResponse?.Project) + } + else { + throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR") + return [] + } } async function updateProjectDates(request: any, actionInUrl: any) { - const { startDate, endDate, projectId } = request?.body?.CampaignDetails; - if ((startDate || endDate) && projectId && actionInUrl == "update") { - const projects = await getRelatedProjects(request); - for (const project of projects) { - project.startDate = startDate || project.startDate; - project.endDate = endDate || project.endDate; - delete project?.address; - } - logger.info( - "Projects related to current Campaign : " + JSON.stringify(projects) - ); - const projectUpdateBody = { - RequestInfo: request?.body?.RequestInfo, - Projects: projects, - }; - const projectUpdateResponse = await httpRequest( - config?.host?.projectHost + config?.paths?.projectUpdate, - projectUpdateBody - ); - if ( - projectUpdateResponse?.Project && - Array.isArray(projectUpdateResponse?.Project) && - projectUpdateResponse?.Project?.length == projects?.length - ) { - logger.info("Project dates updated successfully"); - } else { - throwError("PROJECT", 500, "PROJECT_UPDATE_ERROR"); + const { startDate, endDate, projectId } = request?.body?.CampaignDetails + if ((startDate || endDate) && projectId && actionInUrl == "update") { + const projects = await getRelatedProjects(request); + for (const project of projects) { + project.startDate = startDate || project.startDate; + project.endDate = endDate || project.endDate; + delete project?.address; + } + logger.info("Projects related to current Campaign : " + JSON.stringify(projects)); + const projectUpdateBody = { + RequestInfo: request?.body?.RequestInfo, + Projects: projects + } + const projectUpdateResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectUpdate, projectUpdateBody); + if (projectUpdateResponse?.Project && Array.isArray(projectUpdateResponse?.Project) && projectUpdateResponse?.Project?.length == projects?.length) { + logger.info("Project dates updated successfully") + } + else { + throwError("PROJECT", 500, "PROJECT_UPDATE_ERROR") + } } - } } async function getCodesTarget(request: any, localizationMap?: any) { - let boundaryCodesWhoseTargetsHasToBeUpdated: any = []; - const { tenantId, resources } = request?.body?.CampaignDetails; - const boundaryWithTargetResource = resources?.filter( - (resource: any) => resource?.type == "boundaryWithTarget" - ); - if (boundaryWithTargetResource && boundaryWithTargetResource.length > 0) { - const fileId = boundaryWithTargetResource[0]?.filestoreId; - const fileResponse = await httpRequest( - config.host.filestore + config.paths.filestore + "/url", - {}, - { tenantId: tenantId, fileStoreIds: fileId }, - "get" - ); + const { tenantId, resources } = request?.body?.CampaignDetails; + const boundaryWithTargetResource = resources?.filter((resource: any) => resource?.type == "boundaryWithTarget"); + const fileId = boundaryWithTargetResource[0]?.filestoreId + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileId }, "get"); if (!fileResponse?.fileStoreIds?.[0]?.url) { - throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); + throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); } - const codeColumnName = getLocalizedName( - createAndSearch?.boundaryWithTarget?.boundaryValidation?.column, - localizationMap - ); - const targetData = await getTargetSheetDataAfterCode( - request, - fileResponse?.fileStoreIds?.[0]?.url, - true, - true, - codeColumnName - ); + const codeColumnName = getLocalizedName(createAndSearch?.boundaryWithTarget?.boundaryValidation?.column, localizationMap) + const targetData = await getTargetSheetDataAfterCode(fileResponse?.fileStoreIds?.[0]?.url, true, true, codeColumnName); const boundaryTargetMapping: any = {}; // Iterate through each key in targetData for (const key in targetData) { - // Iterate through each entry in the array under the current key - targetData[key].forEach((entry) => { - // Check if the entry has both "Boundary Code" and "Target at the Selected Boundary level" - if ( - entry[codeColumnName] !== undefined && - entry["Target at the Selected Boundary level"] !== undefined - ) { - // Add the mapping to the boundaryTargetMapping object - boundaryTargetMapping[entry[codeColumnName]] = - entry["Target at the Selected Boundary level"]; - if ( - entry["Parent Target at the Selected Boundary level"] !== 0 && - entry["Parent Target at the Selected Boundary level"] !== - entry["Target at the Selected Boundary level"] - ) { - boundaryCodesWhoseTargetsHasToBeUpdated.push(entry[codeColumnName]); - } - } - }); + // Iterate through each entry in the array under the current key + targetData[key].forEach(entry => { + // Check if the entry has both "Boundary Code" and "Target at the Selected Boundary level" + if (entry[codeColumnName] !== undefined && entry['Target at the Selected Boundary level'] !== undefined) { + // Add the mapping to the boundaryTargetMapping object + boundaryTargetMapping[entry[codeColumnName]] = entry['Target at the Selected Boundary level']; + } + }); } - logger.info( - "Boundary target mapping count" + - Object.keys(boundaryTargetMapping)?.length - ); - request.body.boundaryCodesWhoseTargetsHasToBeUpdated = - boundaryCodesWhoseTargetsHasToBeUpdated; + logger.info("Boundary target mapping count" + Object.keys(boundaryTargetMapping)?.length); return boundaryTargetMapping; - } else return null; } -async function createProject( - request: any, - actionUrl: any, - localizationMap?: any -) { - await persistTrack( - request.body.CampaignDetails.id, - processTrackTypes.targetAndDeliveryRulesCreation, - processTrackStatuses.inprogress - ); - try { - logger.info("Create Projects started for the given Campaign"); - var { tenantId, projectType, projectId } = request?.body?.CampaignDetails; - var boundaries = request?.body?.boundariesCombined; +async function createProject(request: any, actionUrl: any, localizationMap?: any) { + logger.info("Create Projects started for the given Campaign") + var { tenantId, boundaries, projectType, projectId } = request?.body?.CampaignDetails; if (boundaries && projectType && !projectId) { - const projectTypeResponse = await getMDMSV1Data( - {}, - "HCM-PROJECT-TYPES", - "projectTypes", - tenantId - ); - var Projects: any = enrichProjectDetailsFromCampaignDetails( - request?.body?.CampaignDetails, - projectTypeResponse?.filter( - (types: any) => types?.code == projectType - )?.[0] - ); - const projectCreateBody = { - RequestInfo: request?.body?.RequestInfo, - Projects, - }; - boundaries = await reorderBoundaries(request, localizationMap); - let boundariesAlreadyWithProjects: any; - if (request?.body?.parentCampaign) { - // make search to project with parent campaign root project id - const { projectId, tenantId } = request?.body?.parentCampaign; - const projectSearchResponse = - await fetchProjectsWithProjectId(request, projectId, tenantId); - boundariesAlreadyWithProjects = - getBoundaryProjectMappingFromParentCampaign( - request, - projectSearchResponse?.Project?.[0] - ); - } - - const boundaryCodesWhoseTargetsHasToBeUpdated = - request?.body?.boundaryCodesWhoseTargetsHasToBeUpdated; - if (boundaryCodesWhoseTargetsHasToBeUpdated) { - for (const boundary of boundaryCodesWhoseTargetsHasToBeUpdated) { - if ( - boundariesAlreadyWithProjects && - boundariesAlreadyWithProjects.size > 0 && - boundariesAlreadyWithProjects.has(boundary) - ) { - const projectSearchResponse = - await fetchProjectsWithBoundaryCodeAndReferenceId( - boundary, - tenantId, - request?.body?.CampaignDetails?.campaignNumber, - request?.body?.RequestInfo - ); - const projectToUpdate = projectSearchResponse?.Project?.[0]; - if (projectToUpdate) { - const filteredTargets = projectToUpdate.targets.filter( - (e: any) => - e.beneficiaryType == - request?.body?.CampaignDetails?.additionalDetails - ?.beneficiaryType - ); - if (filteredTargets.length == 0) { - projectToUpdate.targets = [ - { - beneficiaryType: - request?.body?.CampaignDetails?.additionalDetails - ?.beneficiaryType, - totalNo: - request?.body?.CampaignDetails?.codesTargetMapping[ - boundary - ], - targetNo: - request?.body?.CampaignDetails?.codesTargetMapping[ - boundary - ], - }, - ]; - } else { - const targetobj = filteredTargets[0]; - (targetobj.totalNo = - request?.body?.CampaignDetails?.codesTargetMapping[boundary]), - (targetobj.targetNo = - request?.body?.CampaignDetails?.codesTargetMapping[ - boundary - ]); - projectToUpdate.targets = [targetobj]; - } - const projectUpdateBody = { - RequestInfo: request?.body?.RequestInfo, - Projects: [projectToUpdate], - }; - - await projectUpdateForTargets( - projectUpdateBody, - request, - boundary - ); - } - } + const projectTypeResponse = await getMDMSV1Data({}, 'HCM-PROJECT-TYPES', "projectTypes", tenantId); + var Projects: any = enrichProjectDetailsFromCampaignDetails(request?.body?.CampaignDetails, projectTypeResponse?.filter((types: any) => types?.code == projectType)?.[0]); + const projectCreateBody = { + RequestInfo: request?.body?.RequestInfo, + Projects } - } - delete request.body.boundaryCodesWhoseTargetsHasToBeUpdated; - for (const boundary of boundaries) { - const boundaryCode = boundary?.code; - // Only proceed if the boundary code is not already mapped to an existing project - if ( - !boundariesAlreadyWithProjects || - (boundariesAlreadyWithProjects.size > 0 && - !boundariesAlreadyWithProjects.has(boundaryCode)) - ) { - // Set the address for the project - Projects[0].address = { - tenantId: tenantId, - boundary: boundaryCode, - boundaryType: boundary?.type, - }; - - // Handle parent project assignment if present in boundaryProjectMapping - const parent = - request?.body?.boundaryProjectMapping?.[boundaryCode]?.parent; - const parentProjectId = - request?.body?.boundaryProjectMapping?.[parent]?.projectId; - - if (parent && parentProjectId) { - await confirmProjectParentCreation(request, parentProjectId); - Projects[0].parent = parentProjectId; - } else { - Projects[0].parent = null; - } - - // Set the reference ID and project targets - Projects[0].referenceID = request?.body?.CampaignDetails?.campaignNumber; - (Projects[0].targets = [ - { - beneficiaryType: - request?.body?.CampaignDetails?.additionalDetails - ?.beneficiaryType, - totalNo: - request?.body?.CampaignDetails?.codesTargetMapping[ - boundaryCode - ], - targetNo: - request?.body?.CampaignDetails?.codesTargetMapping[ - boundaryCode - ], - }, - ]); - await projectCreate(projectCreateBody, request); + await reorderBoundaries(request, localizationMap) + boundaries = request?.body?.CampaignDetails?.boundaries; + for (const boundary of boundaries) { + Projects[0].address = { tenantId: tenantId, boundary: boundary?.code, boundaryType: boundary?.type } + if (request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent) { + const parent = request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent + await confirmProjectParentCreation(request, request?.body?.boundaryProjectMapping?.[parent]?.projectId) + Projects[0].parent = request?.body?.boundaryProjectMapping?.[parent]?.projectId + } + else { + Projects[0].parent = null + } + Projects[0].referenceID = request?.body?.CampaignDetails?.id + Projects[0].targets = [ + { + beneficiaryType: request?.body?.CampaignDetails?.additionalDetails?.beneficiaryType, + totalNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code], + targetNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code] + } + ] + await projectCreate(projectCreateBody, request) } - } - } - } catch (error: any) { - console.log(error); - await persistTrack( - request?.body?.CampaignDetails?.id, - processTrackTypes.targetAndDeliveryRulesCreation, - processTrackStatuses.failed, - { - error: String( - error?.message + - (error?.description ? ` : ${error?.description}` : "") || error - ), - } - ); - throw new Error(error); - } - await persistTrack( - request?.body?.CampaignDetails?.id, - processTrackTypes.targetAndDeliveryRulesCreation, - processTrackStatuses.completed - ); + } } + async function processAfterPersist(request: any, actionInUrl: any) { - try { - const localizationMap = await getLocalizedMessagesHandler( - request, - request?.body?.CampaignDetails?.tenantId - ); - if (request?.body?.CampaignDetails?.action == "create") { - await persistTrack( - request.body.CampaignDetails.id, - processTrackTypes.validation, - processTrackStatuses.completed - ); - await createProjectCampaignResourcData(request); - await createProject(request, actionInUrl, localizationMap); - await enrichAndPersistProjectCampaignRequest( - request, - actionInUrl, - false, - localizationMap - ); - } else { - await updateProjectDates(request, actionInUrl); - await enrichAndPersistProjectCampaignRequest( - request, - actionInUrl, - false, - localizationMap - ); + try { + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.CampaignDetails?.tenantId); + if (request?.body?.CampaignDetails?.action == "create") { + await createProjectCampaignResourcData(request); + await createProject(request, actionInUrl, localizationMap) + await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) + } + else { + await updateProjectDates(request, actionInUrl); + await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) + } + } catch (error: any) { + console.log(error) + logger.error(error) + enrichAndPersistCampaignWithError(request?.body, error) } - delete request.body?.boundariesCombined; - } catch (error: any) { - console.log(error); - logger.error(error); - await enrichAndPersistCampaignWithError(request?.body, error); - } } async function processBasedOnAction(request: any, actionInUrl: any) { - if (actionInUrl == "create") { - request.body.CampaignDetails.id = uuidv4(); - } - await enrichAndPersistProjectCampaignForFirst(request, actionInUrl, true); - if ( - actionInUrl == "create" && - request.body?.parentCampaign && - request?.body?.CampaignDetails?.action === "draft" - ) { - callGenerateWhenChildCampaigngetsCreated(request); - } - processAfterPersist(request, actionInUrl); + if (actionInUrl == "create") { + request.body.CampaignDetails.id = uuidv4() + } + await enrichAndPersistProjectCampaignForFirst(request, actionInUrl, true) + processAfterPersist(request, actionInUrl) } + async function getLocalizedHierarchy(request: any, localizationMap: any) { - var hierarchy = await getHierarchy( - request, - request?.query?.tenantId, - request?.query?.hierarchyType - ); - var modifiedHierarchy = hierarchy.map((ele) => - `${request?.query?.hierarchyType}_${ele}`.toUpperCase() - ); - var resultHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); - return resultHierarchy; -} - -async function appendSheetsToWorkbook( - request: any, - boundaryData: any[], - differentTabsBasedOnLevel: any, - localizationMap?: any, - fileUrl?: any -) { - try { - logger.info( - "Received Boundary data for generating different tabs based on configured boundary level" - ); - const hierarchy: any[] = await getLocalizedHierarchy( - request, - localizationMap - ); - const workbook = getNewExcelWorkbook(); - const type = request?.query?.type; - const headingInSheet = headingMapping?.[type]; - const localisedHeading = getLocalizedName(headingInSheet, localizationMap); - await createReadMeSheet( - request, - workbook, - localisedHeading, - localizationMap - ); - const [ - mainSheetData, - uniqueDistrictsForMainSheet, - districtLevelRowBoundaryCodeMap, - ] = createBoundaryDataMainSheet( - request, - boundaryData, - differentTabsBasedOnLevel, - hierarchy, - localizationMap + var hierarchy = await getHierarchy(request, request?.query?.tenantId, request?.query?.hierarchyType); + var modifiedHierarchy = hierarchy.map((ele) => + `${request?.query?.hierarchyType}_${ele}`.toUpperCase() ); - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - // const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); - const mainSheet = workbook.addWorksheet( - getLocalizedName(getBoundaryTabName(), localizationMap) - ); - const columnWidths = Array(12).fill(30); - mainSheet.columns = columnWidths.map((width) => ({ width })); - // mainSheetData.forEach(row => mainSheet.addRow(row)); - addDataToSheet( - request, - mainSheet, - mainSheetData, - "F3842D", - 30, - false, - true - ); - mainSheet.state = "hidden"; - logger.info("appending different districts tab in the sheet started"); - await appendDistricts( - request, - workbook, - uniqueDistrictsForMainSheet, - differentTabsBasedOnLevel, - boundaryData, - localizationMap, - districtLevelRowBoundaryCodeMap, - hierarchy, - campaignObject, - fileUrl - ); - logger.info("Sheet with different tabs generated successfully"); - return workbook; - } catch (error) { - console.log(error); - throw Error("An error occurred while creating tabs based on district:"); - } -} - -async function appendDistricts( - request: any, - workbook: any, - uniqueDistrictsForMainSheet: any, - differentTabsBasedOnLevel: any, - boundaryData: any, - localizationMap: any, - districtLevelRowBoundaryCodeMap: any, - hierarchy: any, - campaignObject: any, - fileUrl?: any -) { - const configurableColumnHeadersFromSchemaForTargetSheet = - await getConfigurableColumnHeadersFromSchemaForTargetSheet( - request, - hierarchy, - boundaryData, - differentTabsBasedOnLevel, - campaignObject, - localizationMap - ); - let sheetNamesOfProcessedFile: any; - if (fileUrl) { - const processedWorkbook = await getTargetWorkbook(fileUrl, localizationMap); - sheetNamesOfProcessedFile = processedWorkbook.worksheets.map( - (sheet: any) => sheet.name - ); - } - for (const uniqueData of uniqueDistrictsForMainSheet) { - const uniqueDataFromLevelForDifferentTabs = uniqueData.slice( - uniqueData.lastIndexOf("#") + 1 - ); - logger.info( - `generating the boundary data for ${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel}` - ); - const districtDataFiltered = boundaryData.filter( - (boundary: any) => - boundary[differentTabsBasedOnLevel] === - uniqueDataFromLevelForDifferentTabs && - boundary[hierarchy[hierarchy.length - 1]] - ); - const modifiedFilteredData = modifyFilteredData( - districtDataFiltered, - districtLevelRowBoundaryCodeMap.get(uniqueData), - differentTabsBasedOnLevel, - localizationMap - ); - if (modifiedFilteredData?.[0]) { - const newSheetData = [configurableColumnHeadersFromSchemaForTargetSheet]; - for (const data of modifiedFilteredData) { - var rowData: any[] = []; - for (const header of configurableColumnHeadersFromSchemaForTargetSheet) { - rowData.push(data[header] || ""); - } - newSheetData.push(rowData); - } - - await createNewSheet( - request, - workbook, - newSheetData, - uniqueData, - localizationMap, - districtLevelRowBoundaryCodeMap, - configurableColumnHeadersFromSchemaForTargetSheet, - campaignObject, - sheetNamesOfProcessedFile, - fileUrl - ); - logger.info( - `${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel} boundary data generation completed` - ); - } - } -} - -async function createNewSheet( - request: any, - workbook: any, - newSheetData: any, - uniqueData: any, - localizationMap: any, - districtLevelRowBoundaryCodeMap: any, - localizedHeaders: any, - campaignObject: any, - sheetNamesOfProcessedFile: any, - fileUrl?: any -) { - const newSheet = workbook.addWorksheet( - getLocalizedName( - districtLevelRowBoundaryCodeMap.get(uniqueData), - localizationMap - ) - ); - let modifiedNewSheetData: any = newSheetData; - const oldTargetColumnsToHide: any[] = []; - if (fileUrl) { - let processedDistrictSheetData: any; - if ( - sheetNamesOfProcessedFile.includes( - getLocalizedName( - districtLevelRowBoundaryCodeMap.get(uniqueData), - localizationMap - ) - ) - ) { - processedDistrictSheetData = await getSheetData( - fileUrl, - getLocalizedName( - districtLevelRowBoundaryCodeMap.get(uniqueData), - localizationMap - ), - false, - undefined, + var resultHierarchy = getLocalizedHeaders( + modifiedHierarchy, localizationMap - ); - } - modifiedNewSheetData = modifyNewSheetData( - processedDistrictSheetData, - newSheetData, - localizedHeaders, - oldTargetColumnsToHide, - localizationMap - ); - } - addDataToSheet(request, newSheet, modifiedNewSheetData, "F3842D", 40); - if (oldTargetColumnsToHide && oldTargetColumnsToHide.length > 0) { - const columnIndexesToBeHidden: any[] = []; - oldTargetColumnsToHide.forEach((column: any) => { - const localizedColumn = getLocalizedName(column, localizationMap); - const columnIndex = getColumnIndexByHeader(newSheet, localizedColumn); - columnIndexesToBeHidden.push(columnIndex); - }); - hideColumnsOfProcessedFile(newSheet, columnIndexesToBeHidden); - } - let columnsNotToBeFreezed: any; - const boundaryCodeColumnIndex = localizedHeaders.findIndex( - (header: any) => - header === - getLocalizedName(config?.boundary?.boundaryCode, localizationMap) - ); - if ( - isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && - campaignObject.deliveryRules && - campaignObject.deliveryRules.length > 0 - ) { - columnsNotToBeFreezed = localizedHeaders.slice(boundaryCodeColumnIndex + 1); - } else { - const mdmsResponse = await getMdmsDataBasedOnCampaignType( - request, - localizationMap ); - columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; - } - const localizedColumnsNotToBeFreezed = getLocalizedHeaders( - columnsNotToBeFreezed, - localizationMap - ); - lockTargetFields( - newSheet, - localizedColumnsNotToBeFreezed, - boundaryCodeColumnIndex - ); -} - -function modifyFilteredData( - districtDataFiltered: any, - targetBoundaryCode: any, - differentTabsBasedOnLevel: any, - localizationMap?: any -): any { - // Retrieve the localized version of the target boundary code if a localization map is provided - const desiredBoundaryCode = getLocalizedName( - targetBoundaryCode, - localizationMap - ); - // Filter the district data to include only rows where the boundary code matches the desired one - const modifiedFilteredData = districtDataFiltered.filter((row: any) => { - return row[differentTabsBasedOnLevel] == desiredBoundaryCode; - }); - // Return the filtered data - return modifiedFilteredData; -} - -async function generateFilteredBoundaryData( - request: any, - FiltersFromCampaignId: any -) { - const rootBoundary: any = (FiltersFromCampaignId?.Filters?.boundaries).filter( - (boundary: any) => boundary.isRoot - ); - const params = { - ...request?.query, - includeChildren: true, - codes: rootBoundary?.[0]?.code, - }; - const boundaryDataFromRootOnwards = await getBoundaryRelationshipData( - request, - params - ); - logger.info(`filtering the boundaries`); - const filteredBoundaryList = filterBoundaries( - boundaryDataFromRootOnwards, - FiltersFromCampaignId?.Filters - ); - logger.info(`filtered the boundaries based on given criteria`); - return filteredBoundaryList; + return resultHierarchy; +} + + +async function appendSheetsToWorkbook(request: any, boundaryData: any[], differentTabsBasedOnLevel: any, localizationMap?: any) { + try { + logger.info("Received Boundary data for generating different tabs based on configured boundary level"); + const hierarchy: any[] = await getLocalizedHierarchy(request, localizationMap); + const workbook = getNewExcelWorkbook(); + const type = request?.query?.type; + const headingInSheet = headingMapping?.[type]; + const localisedHeading = getLocalizedName(headingInSheet, localizationMap); + await createReadMeSheet(request, workbook, localisedHeading, localizationMap); + const [mainSheetData, uniqueDistrictsForMainSheet, districtLevelRowBoundaryCodeMap] = createBoundaryDataMainSheet(request, boundaryData, differentTabsBasedOnLevel, hierarchy, localizationMap) + const mainSheet = workbook.addWorksheet(getLocalizedName(getBoundaryTabName(), localizationMap)); + const columnWidths = Array(12).fill(30); + mainSheet.columns = columnWidths.map(width => ({ width })); + // mainSheetData.forEach(row => mainSheet.addRow(row)); + addDataToSheet(mainSheet, mainSheetData, 'F3842D', 30, false, true); + logger.info("appending different districts tab in the sheet started") + await appendDistricts(request, workbook, uniqueDistrictsForMainSheet, differentTabsBasedOnLevel, boundaryData, localizationMap, districtLevelRowBoundaryCodeMap, hierarchy); + logger.info("Sheet with different tabs generated successfully"); + return workbook; + } catch (error) { + console.log(error); + throw Error("An error occurred while creating tabs based on district:"); + } +} + + +async function appendDistricts(request: any, workbook: any, uniqueDistrictsForMainSheet: any, differentTabsBasedOnLevel: any, boundaryData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, hierarchy: any) { + const configurableColumnHeadersFromSchemaForTargetSheet = await getConfigurableColumnHeadersFromSchemaForTargetSheet(request, hierarchy, boundaryData, differentTabsBasedOnLevel, localizationMap); + for (const uniqueData of uniqueDistrictsForMainSheet) { + const uniqueDataFromLevelForDifferentTabs = uniqueData.slice(uniqueData.lastIndexOf('#') + 1); + logger.info(`generating the boundary data for ${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel}`) + const districtDataFiltered = boundaryData.filter((boundary: any) => boundary[differentTabsBasedOnLevel] === uniqueDataFromLevelForDifferentTabs && boundary[hierarchy[hierarchy.length - 1]]); + const modifiedFilteredData = modifyFilteredData(districtDataFiltered, districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap); + if (modifiedFilteredData?.[0]) { + const newSheetData = [configurableColumnHeadersFromSchemaForTargetSheet]; + for (const data of modifiedFilteredData) { + var rowData: any[] = []; + for (const header of configurableColumnHeadersFromSchemaForTargetSheet) { + rowData.push(data[header] || ''); + } + newSheetData.push(rowData); + } + await createNewSheet(request, workbook, newSheetData, uniqueData, localizationMap, districtLevelRowBoundaryCodeMap, configurableColumnHeadersFromSchemaForTargetSheet); + logger.info(`${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel} boundary data generation completed`) + } + } } -function filterBoundaries(boundaryData: any[], filters: any): any { - function filterRecursive(boundary: any): any { - const boundaryFilters = filters && filters.boundaries; // Accessing boundaries array from filters object - const filter = boundaryFilters?.find( - (f: any) => - f.code === boundary.code && f.boundaryType === boundary.boundaryType - ); - if (!filter) { - return { - ...boundary, - children: boundary.children.map(filterRecursive), - }; - } - - if (!boundary.children.length) { - if (!filter.includeAllChildren) { - // throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary cannot have includeAllChildren filter false if it does not have any children"); - logger.error( - "Boundary cannot have includeAllChildren filter false if it does not have any children" - ); - } - // If boundary has no children and includeAllChildren is true, return as is - return { - ...boundary, - children: [], - }; - } - - if (filter.includeAllChildren) { - // If includeAllChildren is true, return boundary with all children - return { - ...boundary, - children: boundary.children.map(filterRecursive), - }; - } - - const filteredChildren: any[] = []; - boundary.children.forEach((child: any) => { - const matchingFilter = boundaryFilters.find( - (f: any) => - f.code === child.code && f.boundaryType === child.boundaryType - ); - if (matchingFilter) { - filteredChildren.push(filterRecursive(child)); - } +async function createNewSheet(request: any, workbook: any, newSheetData: any, uniqueData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, localizedHeaders: any) { + const newSheet = workbook.addWorksheet(getLocalizedName(districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap)); + addDataToSheet(newSheet, newSheetData, 'F3842D', 40); + const boundaryCodeColumnIndex = localizedHeaders.findIndex((header: any) => header === getLocalizedName(config?.boundary?.boundaryCode, localizationMap)); + const mdmsResponse = await getMdmsDataBasedOnCampaignType(request, localizationMap) + const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + const localizedColumnsNotToBeFreezed = getLocalizedHeaders(columnsNotToBeFreezed, localizationMap); + lockTargetFields(newSheet, localizedColumnsNotToBeFreezed, boundaryCodeColumnIndex); +} + + + + + +function modifyFilteredData(districtDataFiltered: any, targetBoundaryCode: any, localizationMap?: any): any { + + // Step 2: Slice the boundary code up to the last underscore + const slicedBoundaryCode = targetBoundaryCode.slice(0, targetBoundaryCode.lastIndexOf('_') + 1); + + // Step 3: Filter the rows that contain the sliced boundary code + const modifiedFilteredData = districtDataFiltered.filter((row: any, index: any) => { + // Extract the boundary code from the current row + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap); + const boundaryCode = row[localizedBoundaryCode]; + // Check if the boundary code starts with the sliced boundary code + return boundaryCode.startsWith(slicedBoundaryCode); }); - return { - ...boundary, - children: filteredChildren, + // Step 4: Return the modified filtered data + return modifiedFilteredData; +} + +async function generateFilteredBoundaryData(request: any, FiltersFromCampaignId: any) { + const rootBoundary: any = (FiltersFromCampaignId?.Filters?.boundaries).filter((boundary: any) => boundary.isRoot); + const params = { + ...request?.query, + includeChildren: true, + codes: rootBoundary?.[0]?.code }; - } - const filteredData = boundaryData.map(filterRecursive); - return filteredData; + const boundaryDataFromRootOnwards = await getBoundaryRelationshipData(request, params); + logger.info(`filtering the boundaries`); + const filteredBoundaryList = filterBoundaries(boundaryDataFromRootOnwards, FiltersFromCampaignId?.Filters) + logger.info(`filtered the boundaries based on given criteria`) + return filteredBoundaryList; } -function generateHierarchy(boundaries: any[]) { - // Create an object to store boundary types and their parents - const parentMap: any = {}; - - // Populate the object with boundary types and their parents - for (const boundary of boundaries) { - parentMap[boundary.boundaryType] = boundary.parentBoundaryType; - } - - // Traverse the hierarchy to generate the hierarchy list - const hierarchyList = []; - for (const boundaryType in parentMap) { - if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { - const parentBoundaryType = parentMap[boundaryType]; - if (parentBoundaryType === null) { - // This boundary type has no parent, add it to the hierarchy list - hierarchyList.push(boundaryType); - // Traverse its children recursively - traverseChildren(boundaryType, parentMap, hierarchyList); - } - } - } - return hierarchyList; +function filterBoundaries(boundaryData: any[], filters: any): any { + function filterRecursive(boundary: any): any { + const boundaryFilters = filters && filters.boundaries; // Accessing boundaries array from filters object + const filter = boundaryFilters?.find((f: any) => f.code === boundary.code && f.boundaryType === boundary.boundaryType); + + if (!filter) { + return { + ...boundary, + children: boundary.children.map(filterRecursive) + }; + } + + if (!boundary.children.length) { + if (!filter.includeAllChildren) { + // throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary cannot have includeAllChildren filter false if it does not have any children"); + logger.error("Boundary cannot have includeAllChildren filter false if it does not have any children"); + } + // If boundary has no children and includeAllChildren is true, return as is + return { + ...boundary, + children: [] + }; + } + + if (filter.includeAllChildren) { + // If includeAllChildren is true, return boundary with all children + return { + ...boundary, + children: boundary.children.map(filterRecursive) + }; + } + + const filteredChildren: any[] = []; + boundary.children.forEach((child: any) => { + const matchingFilter = boundaryFilters.find((f: any) => f.code === child.code && f.boundaryType === child.boundaryType); + if (matchingFilter) { + filteredChildren.push(filterRecursive(child)); + } + }); + return { + ...boundary, + children: filteredChildren + }; + } + const filteredData = boundaryData.map(filterRecursive); + return filteredData; } -function traverseChildren(parent: any, parentMap: any, hierarchyList: any[]) { - for (const boundaryType in parentMap) { - if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { - const parentBoundaryType = parentMap[boundaryType]; - if (parentBoundaryType === parent) { - // This boundary type has the current parent, add it to the hierarchy list - hierarchyList.push(boundaryType); - // Traverse its children recursively - traverseChildren(boundaryType, parentMap, hierarchyList); - } + +function generateHierarchy(boundaries: any[]) { + // Create an object to store boundary types and their parents + const parentMap: any = {}; + + // Populate the object with boundary types and their parents + for (const boundary of boundaries) { + parentMap[boundary.boundaryType] = boundary.parentBoundaryType; + } + + // Traverse the hierarchy to generate the hierarchy list + const hierarchyList = []; + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === null) { + // This boundary type has no parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } } - } + return hierarchyList; } -function createBoundaryMap( - boundaries: any[], - boundaryMap: Map -): void { - for (const boundary of boundaries) { - boundaryMap.set(boundary.code, boundary.boundaryType); - if (boundary.children.length > 0) { - createBoundaryMap(boundary.children, boundaryMap); +function traverseChildren(parent: any, parentMap: any, hierarchyList: any[]) { + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === parent) { + // This boundary type has the current parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } } - } } -async function boundaryGeometryManagement(request: any, localizationMap: any) { - try { - logger.info("Boundary Relationship Creation Starts For Geometry Data"); - await autoGenerateBoundaryCodesForGeoJson(request, localizationMap); - } catch (error: any) { - console.log(error); - await handleResouceDetailsError(request, error); - } +function createBoundaryMap(boundaries: any[], boundaryMap: Map): void { + for (const boundary of boundaries) { + boundaryMap.set(boundary.code, boundary.boundaryType); + if (boundary.children.length > 0) { + createBoundaryMap(boundary.children, boundaryMap); + } + } } async function boundaryBulkUpload(request: any, localizationMap?: any) { - try { - logger.info("Boundary Relationship Creation Starts"); - await autoGenerateBoundaryCodes(request, localizationMap); - await generateProcessedFileAndPersist(request); - } catch (error: any) { - console.log(error); - await handleResouceDetailsError(request, error); - } -} - -function updateBoundaryDataForBoundaryManagement( - request: any, - boundaryData: any[], - localizationMap: any -): { updatedData: any[]; latLongData: [number, number][] } { - const latLongData: [number, number][] = []; - const latKey = getLocalizedName("HCM_ADMIN_CONSOLE_LAT", localizationMap); - const longKey = getLocalizedName("HCM_ADMIN_CONSOLE_LONG", localizationMap); - - boundaryData.forEach((row) => { - // Check if the row contains both latitude and longitude keys - if (latKey in row && longKey in row) { - // Push latitude and longitude to the latLongData array - latLongData.push([row[latKey], row[longKey]]); - - // Remove the latitude and longitude from the original row - delete row[latKey]; - delete row[longKey]; - } - }); - - // Return both the updated boundary data and latLongData - return { - updatedData: boundaryData, - latLongData, - }; -} - -async function autoGenerateBoundaryCodesForGeoJson( - request: any, - localizationMap?: any -) { - const { hierarchyType, tenantId } = request?.body?.ResourceDetails || {}; - // const type = request?.body?.ResourceDetails?.type; - const fileResponse = await httpRequest( - config.host.filestore + config.paths.filestore + "/url", - {}, - { tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, - "get" - ); - var boundaryData = await getDataFromGeoJson( - fileResponse?.fileStoreIds?.[0]?.url - ); - const hierarchy = - (await getHierarchy(request, tenantId, hierarchyType)) || []; - const dataFromGeoJson = getGeoJsonData(boundaryData, hierarchy); - const childParentMap = getChildParentMap(dataFromGeoJson); - const countMap = new Map<{ key: string; value: string }, number>(); - const mappingMap = new Map<{ key: string; value: string }, string>(); - const boundaryMap = await getAutoGeneratedBoundaryCodesHandler( - dataFromGeoJson, - childParentMap, - mappingMap, - countMap, - request - ); - logger.info("Boundary Code Auto Generation Completed"); - await createBoundaryEntities(request, boundaryMap); - logger.info( - "waiting for 2 secs to persist the boundary entities before creating boundary relationship" - ); - await new Promise((resolve) => setTimeout(resolve, 2000)); - const modifiedChildParentMap = modifyChildParentMap( - childParentMap, - boundaryMap - ); - await createBoundaryRelationship( - request, - boundaryMap, - modifiedChildParentMap - ); - const boundaryGeoJsonAfterProcessing = addBoundaryCodeToGeoJsonData( - boundaryData, - hierarchy, - boundaryMap - ); - logger.info( - "Initiated the localisation message creation for the uploaded boundary" - ); - transformAndCreateLocalisation(boundaryMap, request); - const boundaryFileDetails: any = await createAndUploadJsonFile( - boundaryGeoJsonAfterProcessing, - request - ); - await updateAndPersistResourceDetails( - request, - boundaryFileDetails, - boundaryData?.name - ); - logger.info("Boundary Relationship Creation Completed"); -} - -async function updateAndPersistResourceDetails( - request: any, - boundaryFileDetails: any, - name: any -) { - const fileStoreId = boundaryFileDetails[0]?.fileStoreId; - const getLatestResourceDetails = await getResourceDetails(request); - - if (getLatestResourceDetails == null) { - request.body.ResourceDetails = { - ...request?.body?.ResourceDetails, - processedFileStoreId: fileStoreId, - status: - request.body.ResourceDetails.status != resourceDataStatuses.invalid - ? resourceDataStatuses.completed - : resourceDataStatuses.invalid, - auditDetails: { - ...request?.body?.ResourceDetails?.auditDetails, - lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, - lastModifiedTime: Date.now(), - }, - additionalDetails: - { - ...request?.body?.ResourceDetails?.additionalDetails, - sheetErrors: request?.body?.additionalDetailsErrors, - source: - request?.body?.ResourceDetails?.additionalDetails?.source == - "microplan" - ? "microplan" - : null, - [name]: [fileStoreId], - }, - }; - } else { - request.body.ResourceDetails = { - ...getLatestResourceDetails, - processedFileStoreId: fileStoreId, - status: - getLatestResourceDetails.status != resourceDataStatuses.invalid - ? resourceDataStatuses.completed - : resourceDataStatuses.invalid, - auditDetails: { - ...getLatestResourceDetails.auditDetails, - lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, - lastModifiedTime: Date.now(), - }, - additionalDetails: - { - ...getLatestResourceDetails.additionalDetails, - sheetErrors: request?.body?.additionalDetailsErrors, - source: - getLatestResourceDetails.additionalDetails?.source == "microplan" - ? "microplan" - : null, - }, - }; - let additionalDetails = request?.body?.ResourceDetails?.additionalDetails; - if (additionalDetails && additionalDetails[name]) { - additionalDetails[name].push(fileStoreId); - } else { - additionalDetails = { ...additionalDetails, [name]: [fileStoreId] }; - } - request.body.ResourceDetails.additionalDetails = additionalDetails; - } - - const persistMessage: any = { ResourceDetails: request.body.ResourceDetails }; - await produceModifiedMessages( - persistMessage, - config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC - ); - logger.info( - `ResourceDetails to persist : ${request.body.ResourceDetails.type}` - ); -} - -async function getResourceDetails(request: any) { - const { tenantId, type, hierarchyType } = - request?.body?.ResourceDetails || request?.query; - const resourceDetails = request?.body?.ResourceDetails; - - request.body.SearchCriteria = request.body.SearchCriteria || {}; - - request.body.SearchCriteria = { - tenantId: tenantId, - type: type, - hierarchyType: hierarchyType, - status: resourceDataStatuses.completed, - }; - - const response = await searchDataService(request); - request.body.ResourceDetails = resourceDetails; - if (response.length > 0) { - response.sort( - (a: any, b: any) => - b.auditDetails.lastModifiedTime - a.auditDetails.lastModifiedTime - ); - return response[0]; - } else { - return null; - } -} -const addBoundaryCodeToGeoJsonData = ( - boundaryData: any, - hiearchy: any, - boundaryMap: Map -) => { - // const objectMap = boundaryMap.forEach((value, key) => {return { key: key.value, value: value }); - // Create the updatedBoundaryMap using a Map - const updatedBoundaryMap = new Map(); - boundaryMap.forEach((value, key) => { - const newKey = key.key + "_" + key.value; // Concatenate key and value - updatedBoundaryMap.set(newKey, value); // Set in the updated map - }); - - // Iterate through the boundary data - boundaryData.features.forEach((feature: any) => { - // Extract the properties object from the feature - const properties = feature.properties; - - // Iterate through the hierarchy - hiearchy.forEach((h: string) => { - // Build the field name - const field = h.toLowerCase() + "_name"; - - // Check if the field exists in the properties object - if (properties[field]) { - const boundaryName = h + "_" + properties[field]; - // Assign the boundary code to the properties object - properties[config.boundary.boundaryCode] = - updatedBoundaryMap.get(boundaryName); // Use .get() to access the Map - } - }); - }); - - return boundaryData; -}; -const getGeoJsonData = (boundaryData: any, hiearchy: any) => { - var data: any = []; - boundaryData.features?.forEach((feature: any) => { - const properties = feature.properties; - var row: any = []; - hiearchy.forEach((h: string) => { - const field = h.toLowerCase() + "_name"; - if (properties[field]) { - const d = { - key: h, - value: properties[field], - }; - row.push(d); - } + try { + logger.info("Boundary Relationship Creation Starts"); + await autoGenerateBoundaryCodes(request, localizationMap); + await generateProcessedFileAndPersist(request); + } + catch (error: any) { + console.log(error) + await handleResouceDetailsError(request, error) + } +} + +const autoGenerateBoundaryCodes = async (request: any, localizationMap?: any) => { + const { hierarchyType, tenantId } = request?.body?.ResourceDetails || {}; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, "get"); + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); + const boundaryData = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, localizedBoundaryTab, false, undefined, localizationMap); + const updatedBoundaryData = updateBoundaryData(boundaryData); + const hierarchy = await getHierarchy(request, tenantId, hierarchyType) || []; + const modifiedBoundaryData = modifyBoundaryDataHeaders(updatedBoundaryData, hierarchy, localizationMap); + const [withBoundaryCode, withoutBoundaryCode] = modifyBoundaryData(modifiedBoundaryData, localizationMap); + const { mappingMap, countMap } = getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode); + const childParentMap = getChildParentMap(withoutBoundaryCode); + const boundaryMap = await getAutoGeneratedBoundaryCodesHandler(withoutBoundaryCode, childParentMap, mappingMap, countMap, request); + logger.info("Boundary Code Auto Generation Completed"); + await createBoundaryEntities(request, boundaryMap); + const modifiedChildParentMap = modifyChildParentMap(childParentMap, boundaryMap); + await createBoundaryRelationship(request, boundaryMap, modifiedChildParentMap); + const boundaryDataForSheet = addBoundaryCodeToData(withBoundaryCode, withoutBoundaryCode, boundaryMap); + logger.info("Initiated the localisation message creation for the uploaded boundary"); + transformAndCreateLocalisation(boundaryMap, request); + const modifiedHierarchy = hierarchy.map(ele => `${hierarchyType}_${ele}`.toUpperCase()) + const headers = [...modifiedHierarchy, config?.boundary?.boundaryCode]; + const data = prepareDataForExcel(boundaryDataForSheet, hierarchy, boundaryMap); + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + const boundarySheetData: any = await createExcelSheet(data, localizedHeaders); + const workbook = getNewExcelWorkbook(); + const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); + addDataToSheet(boundarySheet, boundarySheetData); + const boundaryFileDetails: any = await createAndUploadFile(workbook, request); + request.body.ResourceDetails.processedFileStoreId = boundaryFileDetails?.[0]?.fileStoreId; +} + + + +function updateBoundaryData(boundaryData: any[]): any[] { + const map: Map = new Map(); + const count: Map = new Map(); + + boundaryData.forEach((row) => { + const keys = Object.keys(row); + keys.forEach((key, index) => { + if (index > 0) { + const element = row[key]; + const previousKey = keys[index - 1]; + const previousElement = row[keys[index - 1]]; + const previousElementKey = `${previousKey}:${previousElement}`; + const elementKey = `${key}:${element}`; + + if (!map.has(elementKey)) { + map.set(elementKey, previousElementKey); + count.set(elementKey, 1); + } else { + const currentCount = count.get(elementKey)!; + if (map.get(elementKey) !== previousElementKey) { + map.set(elementKey, previousElementKey); + count.set(elementKey, currentCount + 1); + } + const uniqueCount = count.get(elementKey)!; + const uniqueElement = (uniqueCount > 1) ? `${element}-${(uniqueCount - 1).toString().padStart(2, '0')}` : `${element}`; + row[key] = uniqueElement; + } + } + }); }); - data.push(row); - }); - return data; -}; + return boundaryData; +} -const getDataFromGeoJson = async (url: string) => { - // Define headers for HTTP request - const headers = { - "Content-Type": "application/json", - Accept: "application/json", - }; - logger.info("loading for the file based on fileurl"); - // Make HTTP request to retrieve Excel file as arraybuffer - const responseFile = await httpRequest(url, null, {}, "get", "json", headers); - logger.info("received the file response"); - return responseFile; -}; +function modifyBoundaryDataHeaders(boundaryData: any[], hierarchy: any[], localizationMap?: any) { + const updatedData = boundaryData.map((obj: any) => { + const updatedObj: { [key: string]: string | undefined } = {}; // Updated object with modified keys -const autoGenerateBoundaryCodes = async ( - request: any, - localizationMap?: any -) => { - const { hierarchyType, tenantId } = request?.body?.ResourceDetails || {}; - const hierarchy = - (await getHierarchy(request, tenantId, hierarchyType)) || []; - const headersOfBoundarySheet = hierarchy.map( - (e) => `${hierarchyType.toUpperCase()}_${e.toUpperCase()}` - ); - const localizedHeadersOfBoundarySheet = getLocalizedHeaders( - headersOfBoundarySheet, - localizationMap - ); - const type = request?.body?.ResourceDetails?.type; - const fileResponse = await httpRequest( - config.host.filestore + config.paths.filestore + "/url", - {}, - { tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, - "get" - ); - const localizedBoundaryTab = getLocalizedName( - getBoundaryTabName(), - localizationMap - ); - var boundaryData = await getSheetData( - fileResponse?.fileStoreIds?.[0]?.url, - localizedBoundaryTab, - false, - undefined, - localizationMap - ); - var latLongData: any; - if (type === "boundaryManagement") { - validateBoundarySheetDataInCreateFlow( - boundaryData, - localizedHeadersOfBoundarySheet - ); - const result = await updateBoundaryDataForBoundaryManagement( - request, - boundaryData, - localizationMap - ); - latLongData = result.latLongData; - boundaryData = result.updatedData; - } - const updatedBoundaryData = updateBoundaryData(boundaryData, hierarchy); - const modifiedBoundaryData = modifyBoundaryDataHeaders( - updatedBoundaryData, - hierarchy, - localizationMap - ); - const [withBoundaryCode, withoutBoundaryCode] = modifyBoundaryData( - modifiedBoundaryData, - localizationMap - ); - const { mappingMap, countMap } = - getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode); - const childParentMap = getChildParentMap([ - ...withBoundaryCode, - ...withoutBoundaryCode, - ]); - const boundaryMap = await getAutoGeneratedBoundaryCodesHandler( - withoutBoundaryCode, - childParentMap, - mappingMap, - countMap, - request - ); - logger.info("Boundary Code Auto Generation Completed"); - await createBoundaryEntities(request, boundaryMap); - logger.info( - "waiting for 2 secs to persist the boundary entities before creating boundary relationship" - ); - await new Promise((resolve) => setTimeout(resolve, 2000)); - const modifiedChildParentMap = modifyChildParentMap( - childParentMap, - boundaryMap - ); - await createBoundaryRelationship( - request, - boundaryMap, - modifiedChildParentMap - ); - const boundaryDataForSheet = addBoundaryCodeToData( - withBoundaryCode, - withoutBoundaryCode, - boundaryMap - ); - logger.info( - "Initiated the localisation message creation for the uploaded boundary" - ); - await transformAndCreateLocalisation(boundaryMap, request); - const modifiedHierarchy = hierarchy.map((ele) => - `${hierarchyType}_${ele}`.toUpperCase() - ); - var headers = [...modifiedHierarchy, config?.boundary?.boundaryCode]; - const data = prepareDataForExcel( - boundaryDataForSheet, - hierarchy, - boundaryMap - ); - if (type === "boundaryManagement") { - headers = [ - ...headers, - getLocalizedName("HCM_ADMIN_CONSOLE_LAT", localizationMap), - getLocalizedName("HCM_ADMIN_CONSOLE_LONG", localizationMap), - ]; - data.forEach((row: any[], index: string | number) => { - if (latLongData.length > index) { - row.push(latLongData[index][0], latLongData[index][1]); - } - }); - } - const localizedHeaders = getLocalizedHeaders(headers, localizationMap); - const boundarySheetData: any = await createExcelSheet(data, localizedHeaders); - const workbook = getNewExcelWorkbook(); - const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - addDataToSheet(request, boundarySheet, boundarySheetData, "93C47D", 40, true); - const boundaryFileDetails: any = await createAndUploadFile(workbook, request); - request.body.ResourceDetails.processedFileStoreId = - boundaryFileDetails?.[0]?.fileStoreId; -}; + let hierarchyIndex = 0; // Track the index of the hierarchy array -function updateBoundaryData(boundaryData: any[], hierarchy: any[]): any[] { - const map: Map = new Map(); - const count: Map = new Map(); - - boundaryData.forEach((row) => { - const keys = Object.keys(row).filter((key) => hierarchy.includes(key)); - keys.forEach((key, index) => { - if (index > 0) { - const element = row[key]; - const previousKey = keys[index - 1]; - const previousElement = row[keys[index - 1]]; - const previousElementKey = `${previousKey}:${previousElement}`; - const elementKey = `${key}:${element}`; - - if (!map.has(elementKey)) { - map.set(elementKey, previousElementKey); - count.set(elementKey, 1); - } else { - const currentCount = count.get(elementKey)!; - if (map.get(elementKey) !== previousElementKey) { - map.set(elementKey, previousElementKey); - count.set(elementKey, currentCount + 1); - } - const uniqueCount = count.get(elementKey)!; - const uniqueElement = - uniqueCount > 1 - ? `${element}-${(uniqueCount - 1).toString().padStart(2, "0")}` - : `${element}`; - row[key] = uniqueElement; + for (const key in obj) { + if (key != getLocalizedName(config?.boundary?.boundaryCode, localizationMap)) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + const hierarchyKey = hierarchy[hierarchyIndex]; // Get the key from the hierarchy array + updatedObj[hierarchyKey] = obj[key]; // Map the key to the updated object + hierarchyIndex++; // Move to the next key in the hierarchy array + } + } + else { + updatedObj[key] = obj[key]; + } } - } + + + return updatedObj; }); - }); - return boundaryData; + return updatedData; } -function modifyBoundaryDataHeaders( - boundaryData: any[], - hierarchy: any[], - localizationMap?: any -) { - const updatedData = boundaryData.map((obj: any) => { - const updatedObj: { [key: string]: string | undefined } = {}; // Updated object with modified keys - - let hierarchyIndex = 0; // Track the index of the hierarchy array - - for (const key in obj) { - if ( - key != getLocalizedName(config?.boundary?.boundaryCode, localizationMap) - ) { - if (Object.prototype.hasOwnProperty.call(obj, key)) { - const hierarchyKey = hierarchy[hierarchyIndex]; // Get the key from the hierarchy array - updatedObj[hierarchyKey] = obj[key]; // Map the key to the updated object - hierarchyIndex++; // Move to the next key in the hierarchy array - } - } else { - updatedObj[key] = obj[key]; - } - } +function modifyChildParentMap(childParentMap: Map, boundaryMap: Map): Map { + const modifiedMap: Map = new Map(); - return updatedObj; - }); - return updatedData; -} + // Iterate over each entry in childParentMap + childParentMap.forEach((value, key) => { + // Get the modified key and value from boundaryMap + const modifiedKey = findMapValue(boundaryMap, key) || null; + const modifiedValue = value ? findMapValue(boundaryMap, value) : null; -function modifyChildParentMap( - childParentMap: Map, - boundaryMap: Map -): Map { - const modifiedMap: Map = new Map(); + // Set the modified key-value pair in modifiedMap + modifiedMap.set(modifiedKey, modifiedValue); + }); - // Iterate over each entry in childParentMap - childParentMap.forEach((value, key) => { - // Get the modified key and value from boundaryMap - const modifiedKey = findMapValue(boundaryMap, key) || null; - const modifiedValue = value ? findMapValue(boundaryMap, value) : null; + return modifiedMap; +} - // Set the modified key-value pair in modifiedMap - modifiedMap.set(modifiedKey, modifiedValue); - }); - return modifiedMap; +async function convertSheetToDifferentTabs(request: any, boundaryData: any, differentTabsBasedOnLevel: any, localizationMap?: any) { + // create different tabs on the level of hierarchy we want to + const updatedWorkbook = await appendSheetsToWorkbook(request, boundaryData, differentTabsBasedOnLevel, localizationMap); + // upload the excel and generate file store id + const boundaryDetails = await createAndUploadFile(updatedWorkbook, request); + return boundaryDetails; } -async function convertSheetToDifferentTabs( - request: any, - boundaryData: any, - differentTabsBasedOnLevel: any, - localizationMap?: any, - fileUrl?: any -) { - // create different tabs on the level of hierarchy we want to - const updatedWorkbook = await appendSheetsToWorkbook( - request, - boundaryData, - differentTabsBasedOnLevel, - localizationMap, - fileUrl - ); - // upload the excel and generate file store id - const boundaryDetails = await createAndUploadFile(updatedWorkbook, request); - return boundaryDetails; -} - -async function getBoundaryDataAfterGeneration( - result: any, - request: any, - localizationMap?: any -) { - const fileStoreId = result[0].fileStoreId; - const fileResponse = await httpRequest( - config.host.filestore + config.paths.filestore + "/url", - {}, - { tenantId: request?.query?.tenantId, fileStoreIds: fileStoreId }, - "get" - ); - if (!fileResponse?.fileStoreIds?.[0]?.url) { - throwError("FILE", 400, "INVALID_FILE"); - } - const boundaryData = await getSheetData( - fileResponse?.fileStoreIds?.[0]?.url, - getBoundaryTabName(), - false, - undefined, - localizationMap - ); - return boundaryData; -} - -function getLocalizedName( - expectedName: string, - localizationMap?: { [key: string]: string } -) { - if (!localizationMap || !(expectedName in localizationMap)) { - return expectedName; - } - const localizedName = localizationMap[expectedName]; - return localizedName; +async function getBoundaryDataAfterGeneration(result: any, request: any, localizationMap?: any) { + const fileStoreId = result[0].fileStoreId; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: request?.query?.tenantId, fileStoreIds: fileStoreId }, "get"); + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 400, "INVALID_FILE"); + } + const boundaryData = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, getBoundaryTabName(), false, undefined, localizationMap); + return boundaryData; } -async function getTargetBoundariesRelatedToCampaignId( - request: any, - localizationMap?: any -) { - let CampaignDetailsNew: any; - if (request?.body?.ResourceDetails?.campaignId) { - // const searchBody = { - // RequestInfo: request?.body?.RequestInfo, - const CampaignDetails = { - ids: [request?.body?.ResourceDetails?.campaignId], - tenantId: request?.body?.ResourceDetails?.tenantId, - } - // const req: any = replicateRequest(request, searchBody); - const response = await searchProjectTypeCampaignService(CampaignDetails); - if (response?.CampaignDetails?.[0]) { - CampaignDetailsNew = response?.CampaignDetails?.[0]; - await addBoundariesForData(request, CampaignDetailsNew); - } else { - throwError( - "CAMPAIGN", - 400, - "CAMPAIGN_NOT_FOUND", - "Campaign not found while Validating sheet boundaries" - ); +function getLocalizedName(expectedName: string, localizationMap?: { [key: string]: string }) { + if (!localizationMap || !(expectedName in localizationMap)) { + return expectedName; } - } - return CampaignDetailsNew?.boundaries; + const localizedName = localizationMap[expectedName]; + return localizedName; } -async function getFiltersFromCampaignSearchResponse( - request: any, - responseFromCampaignSearch: any -) { - const boundaries = await getBoundariesFromCampaignSearchResponse( - request, - responseFromCampaignSearch?.CampaignDetails?.[0] - ); - const boundariesModified = boundaries?.map((ele: any) => ({ - ...ele, - boundaryType: ele?.type, - })); - if (!boundariesModified) { - logger.info(`no boundaries found so considering the complete hierarchy`); - return { Filters: null }; - } - logger.info(`boundaries found for filtering`); - return { Filters: { boundaries: boundariesModified } }; -} - -const getConfigurableColumnHeadersBasedOnCampaignType = async ( - request: any, - localizationMap?: any -) => { - try { - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - let campaignType = campaignObject?.projectType; - const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); - campaignType = isSourceMicroplan - ? `${config?.prefixForMicroplanCampaigns}-${campaignType}` - : campaignType; - const isUpdate = request?.body?.parentCampaignObject ? true : false; - const mdmsResponse = await callMdmsTypeSchema( - request, - request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, - isUpdate, - request?.query?.type || request?.body?.ResourceDetails?.type, - campaignType - ); - if (!mdmsResponse || mdmsResponse?.columns.length === 0) { - logger.error( - `Campaign Type ${campaignType} has not any columns configured in schema` - ); - throwError( - "COMMON", - 400, - "SCHEMA_ERROR", - `Campaign Type ${campaignType} has not any columns configured in schema` - ); - } - // Extract columns from the response - const columnsForGivenCampaignId = mdmsResponse?.columns; - - // Get localized headers based on the column names - const headerColumnsAfterHierarchy = getLocalizedHeaders( - columnsForGivenCampaignId, - localizationMap - ); - if ( - !headerColumnsAfterHierarchy.includes( - getLocalizedName(config.boundary.boundaryCode, localizationMap) - ) - ) { - logger.error( - `Column Headers of generated Boundary Template does not have ${getLocalizedName( - config.boundary.boundaryCode, - localizationMap - )} column` - ); - throwError( - "COMMON", - 400, - "VALIDATION_ERROR", - `Column Headers of generated Boundary Template does not have ${getLocalizedName( - config.boundary.boundaryCode, - localizationMap - )} column` - ); - } - return headerColumnsAfterHierarchy; - } catch (error: any) { - console.log(error); - throwError( - "FILE", - 400, - "FETCHING_COLUMN_ERROR", - "Error fetching column Headers From Schema (either boundary code column not found or given Campaign Type not found in schema) Check logs" - ); - } +async function getTargetBoundariesRelatedToCampaignId(request: any, localizationMap?: any) { + let CampaignDetails: any; + if (request?.body?.ResourceDetails?.campaignId) { + const searchBody = { + RequestInfo: request?.body?.RequestInfo, + CampaignDetails: { + ids: [request?.body?.ResourceDetails?.campaignId], + tenantId: request?.body?.ResourceDetails?.tenantId + } + } + const req: any = replicateRequest(request, searchBody) + const response = await searchProjectTypeCampaignService(req) + if (response?.CampaignDetails?.[0]) { + CampaignDetails = response?.CampaignDetails?.[0] + await addBoundariesForData(request, CampaignDetails) + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while Validating sheet boundaries"); + } + } + return CampaignDetails?.boundaries; +} + + +function getFiltersFromCampaignSearchResponse(responseFromCampaignSearch: any) { + const boundaries = responseFromCampaignSearch?.CampaignDetails?.[0]?.boundaries?.map((ele: any) => ({ ...ele, boundaryType: ele?.type })); + if (!boundaries) { + logger.info(`no boundaries found so considering the complete hierarchy`); + return { Filters: null }; + } + logger.info(`boundaries found for filtering`); + return { Filters: { boundaries: boundaries } } }; -async function getFinalValidHeadersForTargetSheetAsPerCampaignType( - request: any, - hierarchy: any[], - differentTabsBasedOnLevel: any, - localizationMap?: any -) { - const modifiedHierarchy = hierarchy.map((ele) => - `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase() - ); - const localizedHierarchy = getLocalizedHeaders( - modifiedHierarchy, - localizationMap - ); - const index = localizedHierarchy.indexOf( - getLocalizedName(differentTabsBasedOnLevel, localizationMap) - ); - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); - var expectedHeadersForTargetSheetUptoHierarchy: any; - if (isSourceMicroplan) { - expectedHeadersForTargetSheetUptoHierarchy = localizedHierarchy; - } else { - expectedHeadersForTargetSheetUptoHierarchy = - index !== -1 - ? localizedHierarchy.slice(index) - : throwError( - "COMMON", - 400, - "VALIDATION_ERROR", - `${differentTabsBasedOnLevel} level not present in the hierarchy` - ); - } - const columnFromSchemaOfTargetTemplate = await generateDynamicTargetHeaders( - request, - campaignObject, - localizationMap - ); - const localizedcolumnFromSchemaOfTargetTemplate = getLocalizedHeaders( - columnFromSchemaOfTargetTemplate, - localizationMap - ); - let updatedLocalizedcolumnFromSchemaOfTargetTemplate = - localizedcolumnFromSchemaOfTargetTemplate; - if (request?.body?.parentCampaignObject) { - updatedLocalizedcolumnFromSchemaOfTargetTemplate = - localizedcolumnFromSchemaOfTargetTemplate - .map((item: any) => `${item}(OLD)`) - .concat(localizedcolumnFromSchemaOfTargetTemplate); - } - const expectedHeadersForTargetSheet = [ - ...expectedHeadersForTargetSheetUptoHierarchy, - getLocalizedName(config?.boundary?.boundaryCode, localizationMap), - ...updatedLocalizedcolumnFromSchemaOfTargetTemplate, - ]; - return expectedHeadersForTargetSheet; -} - -async function getDifferentTabGeneratedBasedOnConfig( - request: any, - boundaryDataGeneratedBeforeDifferentTabSeparation: any, - localizationMap?: any, - fileUrl?: any -) { - var boundaryDataGeneratedAfterDifferentTabSeparation: any = - boundaryDataGeneratedBeforeDifferentTabSeparation; - const boundaryData = await getBoundaryDataAfterGeneration( - boundaryDataGeneratedBeforeDifferentTabSeparation, - request, - localizationMap - ); - let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit( - request, - request?.query?.tenantId - ); - differentTabsBasedOnLevel = getLocalizedName( - `${request?.query?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), - localizationMap - ); - logger.info( - `Boundaries are seperated based on hierarchy type ${differentTabsBasedOnLevel}` - ); - const isKeyOfThatTypePresent = boundaryData.some((data: any) => - data.hasOwnProperty(differentTabsBasedOnLevel) - ); - const boundaryTypeOnWhichWeSplit = boundaryData.filter( - (data: any) => data[differentTabsBasedOnLevel] - ); - if ( - isKeyOfThatTypePresent && - boundaryTypeOnWhichWeSplit.length >= - parseInt(config?.boundary?.numberOfBoundaryDataOnWhichWeSplit) - ) { - logger.info( - `sinces the conditions are matched boundaries are getting splitted into different tabs` - ); - boundaryDataGeneratedAfterDifferentTabSeparation = - await convertSheetToDifferentTabs( - request, - boundaryData, - differentTabsBasedOnLevel, - localizationMap, - fileUrl - ); - } - return boundaryDataGeneratedAfterDifferentTabSeparation; -} - -async function getBoundaryOnWhichWeSplit(request: any, tenantId: any) { - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const MdmsCriteria: any = { - tenantId: tenantId, - schemaCode: `${config.values.moduleName}.${config.masterNameForSplitBoundariesOn}`, - filters: { - hierarchy: responseFromCampaignSearch?.CampaignDetails?.[0].hierarchyType, - }, - }; - const mdmsResponse: any = await searchMDMSDataViaV2Api(MdmsCriteria); - if (!Array.isArray(mdmsResponse?.mdms) || mdmsResponse.mdms.length === 0) { - throwError("MDMS", 500, "MDMS_DATA_NOT_FOUND_ERROR", `${responseFromCampaignSearch?.CampaignDetails?.[0].hierarchyType} hierarchy not configured in mdms data - ${config.values.moduleName}.${config.masterNameForSplitBoundariesOn}`) - } - return mdmsResponse?.mdms?.[0]?.data?.splitBoundariesOn; -} - -function checkIfSourceIsMicroplan(objectWithAdditionalDetails: any): boolean { - return objectWithAdditionalDetails?.additionalDetails?.source === "microplan"; -} - -function createIdRequests(employees: any[]): any[] { - if (employees && Array.isArray(employees) && employees.length > 0) { - const { tenantId } = employees[0]; // Assuming all employees have the same tenantId - return Array.from({ length: employees.length }, () => ({ - tenantId: tenantId, - idName: config?.values?.idgen?.idNameForUserNameGeneration, - idFormat: config?.values?.idgen?.formatForUserName, - })); - } else { - return []; - } -} - -async function createUniqueUserNameViaIdGen(request: any) { - const idgenurl = config?.host?.idGenHost + config?.paths?.idGen; - try { - // Make HTTP request to ID generation service - const result = await httpRequest( - idgenurl, - request?.body, - undefined, - undefined, - undefined, - undefined - ); - // Return null if ID generation fails - return result; - } catch (error: any) { - // Log the error - logger.error(`Error during ID generation: ${error.message}`); - - // Throw a custom error - throwError( - "ID_GENERATION", - 500, - "ID_GENERATION_FAILED", - `Error occurred while generating ID: ${error.message}` - ); - } -} -async function processFetchMicroPlan(request: any) { - try { - logger.info("Waiting for 1 second for templates to get generated..."); - await new Promise((resolve) => setTimeout(resolve, 1000)); +const getConfigurableColumnHeadersBasedOnCampaignType = async (request: any, localizationMap?: any) => { + try { + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; - logger.info("Started processing fetch microplan"); + const mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) + if (!mdmsResponse || mdmsResponse?.columns.length === 0) { + logger.error(`Campaign Type ${campaignType} has not any columns configured in schema`) + throwError("COMMON", 400, "SCHEMA_ERROR", `Campaign Type ${campaignType} has not any columns configured in schema`); + } + // Extract columns from the response + const columnsForGivenCampaignId = mdmsResponse?.columns; + + // Get localized headers based on the column names + const headerColumnsAfterHierarchy = getLocalizedHeaders(columnsForGivenCampaignId, localizationMap); + if (!headerColumnsAfterHierarchy.includes(getLocalizedName(config.boundary.boundaryCode, localizationMap))) { + logger.error(`Column Headers of generated Boundary Template does not have ${getLocalizedName(config.boundary.boundaryCode, localizationMap)} column`) + throwError("COMMON", 400, "VALIDATION_ERROR", `Column Headers of generated Boundary Template does not have ${getLocalizedName(config.boundary.boundaryCode, localizationMap)} column`) + } + return headerColumnsAfterHierarchy; + } catch (error: any) { + console.log(error) + throwError("FILE", 400, "FETCHING_COLUMN_ERROR", "Error fetching column Headers From Schema (either boundary code column not found or given Campaign Type not found in schema) Check logs") + } - const { tenantId } = request.body.MicroplanDetails; - const localizationMap = await getLocalizedMessagesHandler(request, tenantId); - const resources: any = request?.body?.CampaignDetails?.resources || []; - const filteredResources = resources.filter( - (obj: any) => obj?.filestoreId && obj?.resourceId - ); +} - logger.info(`Filtered resources with valid IDs: ${filteredResources?.length}`); - logger.debug(`Filtered resources: ${getFormattedStringForDebug(filteredResources)}`); - const fetchOperations: Promise[] = []; +async function getFinalValidHeadersForTargetSheetAsPerCampaignType(request: any, hierarchy: any[], localizationMap?: any) { + const modifiedHierarchy = hierarchy.map(ele => `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase()); + const localizedHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); + const index = localizedHierarchy.indexOf(getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)); + const expectedHeadersForTargetSheetUptoHierarchy = index !== -1 ? localizedHierarchy.slice(index) : throwError("COMMON", 400, "VALIDATION_ERROR", `${getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)} level not present in the hierarchy`); + const columnFromSchemaOfTargetTemplate = await getConfigurableColumnHeadersBasedOnCampaignType(request); + const localizedcolumnFromSchemaOfTargetTemplate = getLocalizedHeaders(columnFromSchemaOfTargetTemplate, localizationMap) + const expectedHeadersForTargetSheet = [...expectedHeadersForTargetSheetUptoHierarchy, ...localizedcolumnFromSchemaOfTargetTemplate]; + return expectedHeadersForTargetSheet; +} - // Add fetch operations conditionally - if (filteredResources.length === 0 || filteredResources.every((obj: any) => obj?.type !== "facility")) { - fetchOperations.push(fetchFacilityData(request, localizationMap)); - } - if (filteredResources.length === 0 || filteredResources.every((obj: any) => obj?.type !== "boundaryWithTarget")) { - fetchOperations.push(fetchTargetData(request, localizationMap)); - } - if (filteredResources.length === 0 || filteredResources.every((obj: any) => obj?.type !== "user")) { - fetchOperations.push(fetchUserData(request, localizationMap)); +async function getDifferentTabGeneratedBasedOnConfig(request: any, boundaryDataGeneratedBeforeDifferentTabSeparation: any, localizationMap?: any) { + // assigning fileStoreId of a single district tab if criteria for multiple tabs are not met + var boundaryDataGeneratedAfterDifferentTabSeparation: any = boundaryDataGeneratedBeforeDifferentTabSeparation; + const boundaryData = await getBoundaryDataAfterGeneration(boundaryDataGeneratedBeforeDifferentTabSeparation, request, localizationMap); + const differentTabsBasedOnLevel = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); + logger.info(`Boundaries are seperated based on hierarchy type ${differentTabsBasedOnLevel}`) + const isKeyOfThatTypePresent = boundaryData.some((data: any) => data.hasOwnProperty(differentTabsBasedOnLevel)); + const boundaryTypeOnWhichWeSplit = boundaryData.filter((data: any) => data[differentTabsBasedOnLevel]); + if (isKeyOfThatTypePresent && boundaryTypeOnWhichWeSplit.length >= parseInt(config?.boundary?.numberOfBoundaryDataOnWhichWeSplit)) { + logger.info(`sinces the conditions are matched boundaries are getting splitted into different tabs`) + boundaryDataGeneratedAfterDifferentTabSeparation = await convertSheetToDifferentTabs(request, boundaryData, differentTabsBasedOnLevel, localizationMap); } + return boundaryDataGeneratedAfterDifferentTabSeparation; +} - // Run all fetch operations in parallel - await Promise.all(fetchOperations); - logger.info("Updating campaign object after successful fetch microplan..."); - await updateCampaignAfterSearch(request, "MICROPLAN_COMPLETED"); - logger.info("Completed processing fetch microplan"); - } catch (error: any) { - logger.error(`Error during microplan fetch: ${error.message}`); - await updateCampaignAfterSearch(request, "MICROPLAN_FETCH_FAILED"); - } -} -async function updateCampaignAfterSearch(request: any, source = "MICROPLAN_FETCHING") { - logger.info("search campaign with id ") - const { tenantId, campaignId } = request.body.MicroplanDetails; - const campaignDetails = { - tenantId: tenantId, - ids: [campaignId] - } - const searchedCampaignResponse = await searchProjectTypeCampaignService(campaignDetails) - const searchedCamapignObject = searchedCampaignResponse?.CampaignDetails; - if (Array.isArray(searchedCamapignObject) && searchedCamapignObject.length > 0) { - const newRequestBody = { - RequestInfo: request.body.RequestInfo, // Retain the original RequestInfo - CampaignDetails: searchedCamapignObject?.[0] // campaigndetails from search response - }; - const req: any = replicateRequest(request, newRequestBody) - logger.info("Updating the received campaign object, source & its key"); - if (!req.body.CampaignDetails.additionalDetails) { - req.body.CampaignDetails.additionalDetails = {}; - } - req.body.CampaignDetails.additionalDetails.activity = source; - (!req.body?.CampaignDetails?.additionalDetails?.["disease"]) && (req.body.CampaignDetails.additionalDetails["disease"] = "MALARIA"), - (!req.body?.CampaignDetails?.additionalDetails?.["beneficiaryType"]) && (req.body.CampaignDetails.additionalDetails["beneficiaryType"] = - "INDIVIDUAL"); - req.body.CampaignDetails.additionalDetails["key"] = 1; - logger.debug( - `updated object with new source , disease & beneficiarytype ${getFormattedStringForDebug(req.body.CampaignDetails)}` - ); - await updateProjectTypeCampaignService(req); - logger.info("Updated the received campaign object"); - } else { - throwError("CAMPAIGN", 500, "CAMPAIGN_SEARCH_ERROR", "Error in campaign search"); - } -} export { - generateProcessedFileAndPersist, - convertToTypeData, - getChildParentMap, - addBoundaryCodeToData, - prepareDataForExcel, - extractCodesFromBoundaryRelationshipResponse, - searchProjectCampaignResourcData, - processDataSearchRequest, - getCodeMappingsOfExistingBoundaryCodes, - processBasedOnAction, - appendSheetsToWorkbook, - generateFilteredBoundaryData, - generateHierarchy, - createBoundaryMap, - autoGenerateBoundaryCodes, - convertSheetToDifferentTabs, - getBoundaryDataAfterGeneration, - boundaryBulkUpload, - enrichAndPersistCampaignWithError, - getLocalizedName, - reorderBoundaries, - reorderBoundariesOfDataAndValidate, - getTargetBoundariesRelatedToCampaignId, - getFiltersFromCampaignSearchResponse, - getConfigurableColumnHeadersBasedOnCampaignType, - getFinalValidHeadersForTargetSheetAsPerCampaignType, - getDifferentTabGeneratedBasedOnConfig, - checkIfSourceIsMicroplan, - getBoundaryOnWhichWeSplit, - createIdRequests, - createUniqueUserNameViaIdGen, - getRootBoundaryCode, - boundaryGeometryManagement, - getResourceDetails, - enrichInnerCampaignDetails, - processFetchMicroPlan, - updateCampaignAfterSearch, - processBoundary, -}; + generateProcessedFileAndPersist, + convertToTypeData, + getChildParentMap, + addBoundaryCodeToData, + prepareDataForExcel, + extractCodesFromBoundaryRelationshipResponse, + searchProjectCampaignResourcData, + processDataSearchRequest, + getCodeMappingsOfExistingBoundaryCodes, + processBasedOnAction, + appendSheetsToWorkbook, + generateFilteredBoundaryData, + generateHierarchy, + createBoundaryMap, + autoGenerateBoundaryCodes, + convertSheetToDifferentTabs, + getBoundaryDataAfterGeneration, + boundaryBulkUpload, + enrichAndPersistCampaignWithError, + getLocalizedName, + reorderBoundaries, + reorderBoundariesOfDataAndValidate, + getTargetBoundariesRelatedToCampaignId, + getFiltersFromCampaignSearchResponse, + getConfigurableColumnHeadersBasedOnCampaignType, + getFinalValidHeadersForTargetSheetAsPerCampaignType, + getDifferentTabGeneratedBasedOnConfig +} diff --git a/health-services/project-factory/src/server/utils/excelUtils.ts b/health-services/project-factory/src/server/utils/excelUtils.ts index f640b3ddcd8..8624ed7b977 100644 --- a/health-services/project-factory/src/server/utils/excelUtils.ts +++ b/health-services/project-factory/src/server/utils/excelUtils.ts @@ -3,9 +3,6 @@ import { changeFirstRowColumnColour, throwError } from "./genericUtils"; import { httpRequest } from "./request"; import { logger } from "./logger"; import config from "../config"; -import { freezeUnfreezeColumnsForProcessedFile, getColumnIndexByHeader, hideColumnsOfProcessedFile } from "./onGoingCampaignUpdateUtils"; -import { getLocalizedName } from "./campaignUtils"; -import createAndSearch from "../config/createAndSearch"; /** * Function to create a new Excel workbook using the ExcelJS library * @returns {ExcelJS.Workbook} - A new Excel workbook object @@ -18,7 +15,7 @@ const getNewExcelWorkbook = () => { // Function to retrieve workbook from Excel file URL and sheet name const getExcelWorkbookFromFileURL = async ( fileUrl: string, - sheetName?: string + sheetName: string ) => { // Define headers for HTTP request const headers = { @@ -37,23 +34,20 @@ const getExcelWorkbookFromFileURL = async ( ); logger.info("received the file response"); - + // Create a new workbook instance const workbook = getNewExcelWorkbook(); await workbook.xlsx.load(responseFile); logger.info("workbook created based on the fileresponse"); - - if (sheetName) { - // Check if the specified sheet exists in the workbook - const worksheet = workbook.getWorksheet(sheetName); - if (!worksheet) { - throwError( - "FILE", - 400, - "INVALID_SHEETNAME", - `Sheet with name "${sheetName}" is not present in the file.` - ); - } + // Check if the specified sheet exists in the workbook + const worksheet = workbook.getWorksheet(sheetName); + if (sheetName && !worksheet) { + throwError( + "FILE", + 400, + "INVALID_SHEETNAME", + `Sheet with name "${sheetName}" is not present in the file.` + ); } // Return the workbook @@ -61,7 +55,7 @@ const getExcelWorkbookFromFileURL = async ( }; function updateFontNameToRoboto(worksheet: ExcelJS.Worksheet) { - worksheet?.eachRow({ includeEmpty: true }, (row) => { + worksheet.eachRow({ includeEmpty: true }, (row) => { row.eachCell({ includeEmpty: true }, (cell) => { // Preserve existing font properties const existingFont = cell.font || {}; @@ -77,8 +71,8 @@ function updateFontNameToRoboto(worksheet: ExcelJS.Worksheet) { function formatWorksheet(worksheet: any, datas: any, headerSet: any) { // Add empty rows after the main header - // worksheet.addRow([]); - // worksheet.addRow([]); + worksheet.addRow([]); + worksheet.addRow([]); worksheet.addRow([]); // Add the data rows with text wrapping @@ -102,7 +96,7 @@ function formatWorksheet(worksheet: any, datas: any, headerSet: any) { worksheet.getColumn(1).width = 130; logger.info(`Freezing the whole sheet ${worksheet.name}`); - worksheet?.eachRow((row: any) => { + worksheet.eachRow((row: any) => { row.eachCell((cell: any) => { cell.protection = { locked: true }; }); @@ -110,7 +104,7 @@ function formatWorksheet(worksheet: any, datas: any, headerSet: any) { worksheet.protect('passwordhere', { selectLockedCells: true }); } -function performUnfreezeCells(sheet: any, localizationMap?: any, fileUrl?: any) { +function performUnfreezeCells(sheet: any) { logger.info(`Unfreezing the sheet ${sheet.name}`); let lastFilledColumn = 1; @@ -134,7 +128,7 @@ function performUnfreezeCells(sheet: any, localizationMap?: any, fileUrl?: any) function performFreezeWholeSheet(sheet: any) { logger.info(`Freezing the whole sheet ${sheet.name}`); - sheet?.eachRow((row: any) => { + sheet.eachRow((row: any) => { row.eachCell((cell: any) => { cell.protection = { locked: true }; }); @@ -142,127 +136,59 @@ function performFreezeWholeSheet(sheet: any) { sheet.protect('passwordhere', { selectLockedCells: true }); } -// Function to add data to the sheet -function addDataToSheet( - request: any, - sheet: any, - sheetData: any, - firstRowColor: string = '93C47D', - columnWidth: number = 40, - frozeCells: boolean = false, - frozeWholeSheet: boolean = false, - localizationMap?: any, - fileUrl?: any, - schema?: any -) { +function addDataToSheet(sheet: any, sheetData: any, firstRowColor: any = '93C47D', columnWidth = 40, frozeCells = false, frozeWholeSheet = false) { sheetData?.forEach((row: any, index: number) => { - const worksheetRow = sheet.addRow(row); - if (index === 0) { - formatFirstRow(worksheetRow, sheet, firstRowColor, columnWidth, frozeCells); - } else { - formatOtherRows(worksheetRow, frozeCells); - } - }); - finalizeSheet(request, sheet, frozeCells, frozeWholeSheet, localizationMap, fileUrl, schema); -} - - -// Function to format the first row -function formatFirstRow(row: any, sheet: any, firstRowColor: string, columnWidth: number, frozeCells: boolean) { - row.eachCell((cell: any, colNumber: number) => { - setFirstRowCellStyles(cell, firstRowColor, frozeCells); - adjustColumnWidth(sheet, colNumber, columnWidth); - adjustRowHeight(row, cell, columnWidth); - }); -} -// Function to set styles for the first row's cells -function setFirstRowCellStyles(cell: any, firstRowColor: string, frozeCells: boolean) { - cell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: firstRowColor } - }; - - cell.font = { bold: true }; - - if (frozeCells) { - cell.protection = { locked: true }; - } + // Apply fill color to each cell in the first row and make cells bold + if (index === 0) { + worksheetRow.eachCell((cell: any, colNumber: number) => { + // Set cell fill color + cell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: firstRowColor } // Green color + }; + + // Set font to bold + cell.font = { bold: true }; - cell.alignment = { vertical: 'top', horizontal: 'left', wrapText: true }; -} + // Enable text wrapping + cell.alignment = { wrapText: true }; -// Function to adjust column width -function adjustColumnWidth(sheet: any, colNumber: number, columnWidth: number) { - sheet.getColumn(colNumber).width = columnWidth; -} + // Optionally lock the cell + if (frozeCells) { + cell.protection = { locked: true }; + } -// Function to adjust row height based on content -function adjustRowHeight(row: any, cell: any, columnWidth: number) { - const text = cell.value ? cell.value.toString() : ''; - const lines = Math.ceil(text.length / (columnWidth - 2)); // Approximate number of lines - row.height = Math.max(row.height ?? 0, lines * 15); -} + // Update column width based on the length of the cell's text + const currentWidth = sheet.getColumn(colNumber).width || columnWidth; // Default width or current width + const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding + sheet.getColumn(colNumber).width = newWidth; + }); -// Function to format cells in other rows -function formatOtherRows(row: any, frozeCells: boolean) { - row.eachCell((cell: any) => { - if (frozeCells) { - cell.protection = { locked: true }; } + worksheetRow.eachCell((cell: any) => { + if (frozeCells) { + cell.protection = { locked: true }; + } + }); }); -} -// Function to finalize the sheet settings -function finalizeSheet(request: any, sheet: any, frozeCells: boolean, frozeWholeSheet: boolean, localizationMap?: any, fileUrl?: any, schema?: any) { - const type = (request?.query?.type || request?.body?.ResourceDetails?.type); - const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; - const createAndSearchConfig = createAndSearch[typeWithoutWith]; - const columnIndexesToBeFreezed: any = []; - const columnIndexesToBeHidden: any = []; + // Protect the entire sheet to enable cell protection settings if (frozeCells) { - performUnfreezeCells(sheet, localizationMap, fileUrl); + performUnfreezeCells(sheet); } if (frozeWholeSheet) { performFreezeWholeSheet(sheet); } - let columnsToBeFreezed: any[] = []; - let columnsToHide: any[] = []; - if (fileUrl) { - columnsToHide = ["HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD",...schema?.columnsToHide]; - columnsToHide.forEach((column: any) => { - const localizedColumn = getLocalizedName(column, localizationMap); - const columnIndex = getColumnIndexByHeader(sheet, localizedColumn); - columnIndexesToBeHidden.push(columnIndex); - }); - - columnsToBeFreezed = ["HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", ...schema?.columnsToBeFreezed] - columnsToBeFreezed.forEach((column: any) => { - const localizedColumn = getLocalizedName(column, localizationMap); - const columnIndex = getColumnIndexByHeader(sheet, localizedColumn); - columnIndexesToBeFreezed.push(columnIndex); - }); - const activeColumnWhichIsNotToBeFreezed = createAndSearchConfig?.activeColumnName; - const boundaryCodeMandatoryColumnWhichIsNotToBeFreezed = getLocalizedName(config?.boundary?.boundaryCodeMandatory, localizationMap); - const localizedActiveColumnWhichIsNotToBeFreezed = getLocalizedName(activeColumnWhichIsNotToBeFreezed, localizationMap); - const columnIndexOfActiveColumn = getColumnIndexByHeader(sheet, localizedActiveColumnWhichIsNotToBeFreezed); - const columnIndexOfBoundaryCodeMandatory = getColumnIndexByHeader(sheet, boundaryCodeMandatoryColumnWhichIsNotToBeFreezed); - freezeUnfreezeColumnsForProcessedFile(sheet, columnIndexesToBeFreezed, [columnIndexOfActiveColumn, columnIndexOfBoundaryCodeMandatory]); // Example columns to freeze and unfreeze - hideColumnsOfProcessedFile(sheet, columnIndexesToBeHidden); - } updateFontNameToRoboto(sheet); - sheet.views = [{ state: 'frozen', ySplit: 1, zoomScale: 110 }]; } - - - function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCodeColumnIndex: any) { // Make every cell locked by default - newSheet?.eachRow((row: any) => { + newSheet.eachRow((row: any) => { row.eachCell((cell: any) => { cell.protection = { locked: true }; }); @@ -278,7 +204,7 @@ function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCod const targetColumnNumber = headers.indexOf(header) + 1; // Excel columns are 1-based logger.info(`Header: ${header}, Target Column Index: ${targetColumnNumber}`); if (targetColumnNumber > -1) { - newSheet?.eachRow((row: any, rowNumber: number) => { + newSheet.eachRow((row: any, rowNumber: number) => { changeFirstRowColumnColour(newSheet, 'B6D7A8', targetColumnNumber); if (rowNumber === 1) return; @@ -305,4 +231,4 @@ function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCod } -export { getNewExcelWorkbook, getExcelWorkbookFromFileURL, formatWorksheet, addDataToSheet, lockTargetFields, updateFontNameToRoboto, formatFirstRow, formatOtherRows, finalizeSheet }; +export { getNewExcelWorkbook, getExcelWorkbookFromFileURL, formatWorksheet, addDataToSheet, lockTargetFields, updateFontNameToRoboto }; diff --git a/health-services/project-factory/src/server/utils/generateUtils.ts b/health-services/project-factory/src/server/utils/generateUtils.ts deleted file mode 100644 index 83a2ec08ce1..00000000000 --- a/health-services/project-factory/src/server/utils/generateUtils.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { getLocalizedMessagesHandler, processGenerate, replicateRequest, throwError } from "./genericUtils"; -import _ from 'lodash'; -import { getFormattedStringForDebug, logger } from "./logger"; -import { getBoundarySheetData } from "../api/genericApis"; -import { getLocalisationModuleName } from "./localisationUtils"; - -// Now you can use Lodash functions with the "_" prefix, e.g., _.isEqual(), _.sortBy(), etc. -function extractProperties(obj: any) { - return { - code: obj.code || null, - includeAllChildren: obj.includeAllChildren || null, - isRoot: obj.isRoot || null - }; -} - -function areBoundariesSame(existingBoundaries: any, currentBoundaries: any) { - if (!existingBoundaries || !currentBoundaries) return false; - if (existingBoundaries.length !== currentBoundaries.length) return false; - const existingSetOfBoundaries = new Set(existingBoundaries.map((exboundary: any) => JSON.stringify(extractProperties(exboundary)))); - const currentSetOfBoundaries = new Set(currentBoundaries.map((currboundary: any) => JSON.stringify(extractProperties(currboundary)))); - return _.isEqual(existingSetOfBoundaries, currentSetOfBoundaries); -} -function isCampaignTypeSame(request: any) { - const existingCampaignType = request?.body?.ExistingCampaignDetails?.projectType; - const currentCampaignType = request?.body?.CampaignDetails?.projectType; - return _.isEqual(existingCampaignType, currentCampaignType); -} - -async function callGenerateIfBoundariesOrCampaignTypeDiffer(request: any) { - try { - const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; - const boundaries = request?.body?.boundariesCombined - if (ExistingCampaignDetails) { - if (!areBoundariesSame(ExistingCampaignDetails?.boundaries, boundaries) || isSourceDifferent(request) || !isCampaignTypeSame(request)) { - logger.info("Boundaries or Campaign Type differ, generating new resources"); - // Apply 2-second timeout after the condition check - await new Promise(resolve => setTimeout(resolve, 2000)); - - const newRequestBody = { - RequestInfo: request?.body?.RequestInfo, - Filters: { - boundaries: boundaries - } - }; - - const { query } = request; - const params = { - tenantId: request?.body?.CampaignDetails?.tenantId, - forceUpdate: 'true', - hierarchyType: request?.body?.CampaignDetails?.hierarchyType, - campaignId: request?.body?.CampaignDetails?.id - }; - logger.info(`generating new resources for the campaignId: ${request?.body?.CampaignDetails?.id}`); - logger.debug(`boundaries of the generate request : ${getFormattedStringForDebug(boundaries)}`) - const newParamsBoundary = { ...query, ...params, type: "boundary" }; - const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); - await callGenerate(newRequestBoundary, "boundary"); - - const newParamsFacilityWithBoundary = { ...query, ...params, type: "facilityWithBoundary" }; - const newRequestFacilityWithBoundary = replicateRequest(request, newRequestBody, newParamsFacilityWithBoundary); - await callGenerate(newRequestFacilityWithBoundary, "facilityWithBoundary"); - - const newParamsUserWithBoundary = { ...query, ...params, type: "userWithBoundary" }; - const newRequestUserWithBoundary = replicateRequest(request, newRequestBody, newParamsUserWithBoundary); - await callGenerate(newRequestUserWithBoundary, "userWithBoundary"); - } - } - } catch (error: any) { - logger.error(error); - throwError("COMMON", 400, "GENERATE_ERROR", `Error while generating user/facility/boundary: ${error.message}`); - } -} - -function isSourceDifferent(request: any){ - const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; - const CampaignDetails = request?.body?.CampaignDetails; - - if(CampaignDetails.additionalDetails.source !== ExistingCampaignDetails.additionalDetails.source){ - return true; - } - return false; -} - -async function callGenerate(request: any, type: any, enableCaching = false) { - logger.info(`calling generate api for type ${type}`); - if (type === "facilityWithBoundary" || type == "userWithBoundary") { - const { hierarchyType } = request.query; - const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler( - request, - request.query.tenantId, - getLocalisationModuleName(hierarchyType) - ); - const localizationMapModule = await getLocalizedMessagesHandler(request, request.query.tenantId); - const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; - const filteredBoundary = await getBoundarySheetData(request, localizationMap); - await processGenerate(request, enableCaching, filteredBoundary); - } else { - await processGenerate(request, enableCaching); - } -} - - - -export { callGenerateIfBoundariesOrCampaignTypeDiffer, callGenerate, areBoundariesSame } diff --git a/health-services/project-factory/src/server/utils/genericUtils.ts b/health-services/project-factory/src/server/utils/genericUtils.ts index 2380ecbd795..fa3c194b8ca 100644 --- a/health-services/project-factory/src/server/utils/genericUtils.ts +++ b/health-services/project-factory/src/server/utils/genericUtils.ts @@ -2,23 +2,20 @@ import { NextFunction, Request, Response } from "express"; import { httpRequest, defaultheader } from "./request"; import config, { getErrorCodes } from "../config/index"; import { v4 as uuidv4 } from 'uuid'; -import { produceModifiedMessages } from "../kafka/Producer"; +import { produceModifiedMessages } from "../kafka/Listener"; import { generateHierarchyList, getAllFacilities, getCampaignSearchResponse, getHierarchy } from "../api/campaignApis"; -import { getBoundarySheetData, getSheetData, createAndUploadFile, createExcelSheet, getTargetSheetData, callMdmsData, callMdmsTypeSchema, getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement } from "../api/genericApis"; +import { getBoundarySheetData, getSheetData, createAndUploadFile, createExcelSheet, getTargetSheetData, callMdmsData, callMdmsTypeSchema } from "../api/genericApis"; import { logger } from "./logger"; -import { checkIfSourceIsMicroplan, getConfigurableColumnHeadersBasedOnCampaignType, getDifferentTabGeneratedBasedOnConfig, getLocalizedName } from "./campaignUtils"; +import { getConfigurableColumnHeadersBasedOnCampaignType, getDifferentTabGeneratedBasedOnConfig, getLocalizedName } from "./campaignUtils"; import Localisation from "../controllers/localisationController/localisation.controller"; import { executeQuery } from "./db"; import { generatedResourceTransformer } from "./transforms/searchResponseConstructor"; import { generatedResourceStatuses, headingMapping, resourceDataStatuses } from "../config/constants"; -import { getLocaleFromRequest, getLocaleFromRequestInfo, getLocalisationModuleName } from "./localisationUtils"; -import { getBoundaryColumnName, getBoundaryTabName, getLatLongMapForBoundaryCodes } from "./boundaryUtils"; -import { getBoundaryDataService, searchDataService } from "../service/dataManageService"; +import { getLocaleFromRequest, getLocalisationModuleName } from "./localisationUtils"; +import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; +import { getBoundaryDataService } from "../service/dataManageService"; import { addDataToSheet, formatWorksheet, getNewExcelWorkbook, updateFontNameToRoboto } from "./excelUtils"; import createAndSearch from "../config/createAndSearch"; -import { generateDynamicTargetHeaders } from "./targetUtils"; -import { buildSearchCriteria, checkAndGiveIfParentCampaignAvailable, fetchFileUrls, getCreatedResourceIds, modifyProcessedSheetData } from "./onGoingCampaignUpdateUtils"; -import { getReadMeConfigForMicroplan, getRolesForMicroplan, getUserDataFromMicroplanSheet, isMicroplanRequest, modifyBoundaryIfSourceMicroplan } from "./microplanUtils"; const NodeCache = require("node-cache"); const updateGeneratedResourceTopic = config?.kafka?.KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC; @@ -54,12 +51,6 @@ const throwErrorViaRequest = (message: any = "Internal Server Error") => { } }; -function shutdownGracefully() { - logger.info('Shutting down gracefully...'); - // Perform any cleanup tasks here, like closing database connections - process.exit(1); // Exit with a non-zero code to indicate an error -} - function capitalizeFirstLetter(str: string | undefined) { if (!str) return str; return str.charAt(0).toUpperCase() + str.slice(1); @@ -249,47 +240,27 @@ async function generateActivityMessage(tenantId: any, requestBody: any, requestP /* Fetches data from the database */ async function searchGeneratedResources(request: any) { try { - const { type, tenantId, hierarchyType, id, status, campaignId } = request.query; - let queryString = `SELECT * FROM ${config?.DB_CONFIG.DB_GENERATED_RESOURCE_DETAILS_TABLE_NAME} WHERE `; - let queryConditions: string[] = []; + const { type } = request.query; + const { tenantId, hierarchyType } = request.query; + const status = generatedResourceStatuses.completed; + let queryResult: any; + let queryString: string; let queryValues: any[] = []; - if (id) { - queryConditions.push(`id = $${queryValues.length + 1}`); - queryValues.push(id); - } - if (type) { - queryConditions.push(`type = $${queryValues.length + 1}`); - queryValues.push(type); - } - if (hierarchyType) { - queryConditions.push(`hierarchyType = $${queryValues.length + 1}`); - queryValues.push(hierarchyType); + queryString = `SELECT * FROM ${config?.DB_CONFIG.DB_GENERATED_RESOURCE_DETAILS_TABLE_NAME} WHERE `; + // query for download with id + if (request?.query?.id) { + queryString += "id = $1 AND type = $2 AND hierarchytype = $3 AND tenantid = $4 "; + queryValues = [request.query.id, type, hierarchyType, tenantId]; } - if (tenantId) { - queryConditions.push(`tenantId = $${queryValues.length + 1}`); - queryValues.push(tenantId); - } - if (campaignId) { - queryConditions.push(`campaignId = $${queryValues.length + 1}`); - queryValues.push(campaignId); - } - if (status) { - const statusArray = status.split(',').map((s: any) => s.trim()); - const statusConditions = statusArray.map((_: any, index: any) => `status = $${queryValues.length + index + 1}`); - queryConditions.push(`(${statusConditions.join(' OR ')})`); - queryValues.push(...statusArray); + else { + queryString += "type = $1 AND hierarchytype = $2 AND tenantid = $3 AND status =$4 "; + queryValues = [type, hierarchyType, tenantId, status]; } - - queryString += queryConditions.join(" AND "); - - // Add sorting and limiting - queryString += " ORDER BY createdTime DESC OFFSET 0 LIMIT 1"; - - const queryResult = await executeQuery(queryString, queryValues); + queryResult = await executeQuery(queryString, queryValues); return generatedResourceTransformer(queryResult?.rows); - } catch (error: any) { - console.log(error) + } + catch (error: any) { logger.error(`Error fetching data from the database: ${error.message}`); throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", error?.message); return null; // Return null in case of an error @@ -329,8 +300,7 @@ async function generateNewRequestObject(request: any) { lastModifiedBy: request?.body?.RequestInfo?.userInfo.uuid, }, additionalDetails: additionalDetails, - count: null, - campaignId: request?.query?.campaignId + count: null }; return [newEntry]; } @@ -363,74 +333,40 @@ async function getFinalUpdatedResponse(result: any, responseData: any, request: -async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResource: any, request: any, enableCaching = false, filteredBoundary?: any) { +async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResource: any, request: any) { try { const { type, hierarchyType } = request?.query; generatedResource = { generatedResource: newEntryResponse } // send message to create toppic logger.info(`processing the generate request for type ${type}`) - await produceModifiedMessages(generatedResource, createGeneratedResourceTopic); + produceModifiedMessages(generatedResource, createGeneratedResourceTopic); const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; - let fileUrlResponse: any; - if (type != 'boundaryManagement' && request?.query?.campaignId != 'default' && type != 'boundaryGeometryManagement') { - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - logger.info(`checks for parent campaign for type: ${type}`) - await checkAndGiveIfParentCampaignAvailable(request, campaignObject); - } - if (request?.body?.parentCampaignObject) { - const resourcesOfParentCampaign = request?.body?.parentCampaignObject?.resources; - const createdResourceId = getCreatedResourceIds(resourcesOfParentCampaign, type); - logger.info(` found createdResourceId as ${createdResourceId} `); - const searchCriteria = buildSearchCriteria(request, createdResourceId, type); - const responseFromDataSearch = await searchDataService(replicateRequest(request, searchCriteria)); - - const processedFileStoreIdForUSerOrFacility = responseFromDataSearch?.[0]?.processedFilestoreId; - fileUrlResponse = await fetchFileUrls(request, processedFileStoreIdForUSerOrFacility); - - } if (type === 'boundary') { // get boundary data from boundary relationship search api logger.info("Generating Boundary Data") - const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request, enableCaching); + const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request); logger.info(`Boundary data generated successfully: ${JSON.stringify(boundaryDataSheetGeneratedBeforeDifferentTabSeparation)}`); // get boundary sheet data after being generated - var boundaryDataSheetGeneratedAfterDifferentTabSeparation = boundaryDataSheetGeneratedBeforeDifferentTabSeparation; logger.info("generating different tabs logic ") - boundaryDataSheetGeneratedAfterDifferentTabSeparation = await getDifferentTabGeneratedBasedOnConfig(request, boundaryDataSheetGeneratedBeforeDifferentTabSeparation, localizationMap, fileUrlResponse?.fileStoreIds?.[0]?.url) + const boundaryDataSheetGeneratedAfterDifferentTabSeparation = await getDifferentTabGeneratedBasedOnConfig(request, boundaryDataSheetGeneratedBeforeDifferentTabSeparation, localizationMap) logger.info(`Different tabs based on level configured generated, ${JSON.stringify(boundaryDataSheetGeneratedAfterDifferentTabSeparation)}`) const finalResponse = await getFinalUpdatedResponse(boundaryDataSheetGeneratedAfterDifferentTabSeparation, newEntryResponse, request); const generatedResourceNew: any = { generatedResource: finalResponse } // send to update topic - await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); request.body.generatedResource = finalResponse; } - else if (type == 'boundaryManagement' || type === 'boundaryGeometryManagement') { - // get boundary data from boundary relationship search api - logger.info("Generating Boundary Data") - const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request, false); - logger.info(`Boundary data generated successfully: ${JSON.stringify(boundaryDataSheetGeneratedBeforeDifferentTabSeparation)}`); - // get boundary sheet data after being generated - const finalResponse = await getFinalUpdatedResponse(boundaryDataSheetGeneratedBeforeDifferentTabSeparation, newEntryResponse, request); - const generatedResourceNew: any = { generatedResource: finalResponse } - // send to update topic - await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); - request.body.generatedResource = finalResponse; - logger.info("generation completed for boundary management create flow") - } else if (type == "facilityWithBoundary" || type == 'userWithBoundary') { - await processGenerateRequest(request, localizationMap, filteredBoundary, fileUrlResponse?.fileStoreIds?.[0]?.url); + await processGenerateRequest(request, localizationMap); const finalResponse = await getFinalUpdatedResponse(request?.body?.fileDetails, newEntryResponse, request); const generatedResourceNew: any = { generatedResource: finalResponse } - await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); request.body.generatedResource = finalResponse; } - } - catch (error: any) { - console.log(error) - await handleGenerateError(newEntryResponse, generatedResource, error); + } catch (error: any) { + handleGenerateError(newEntryResponse, generatedResource, error); } } @@ -484,81 +420,13 @@ function correctParentValues(campaignDetails: any) { return campaignDetails; } -function setDropdownFromSchema(request: any, schema: any, localizationMap?: { [key: string]: string }) { - const dropdowns = Object.entries(schema.properties) - .filter(([key, value]: any) => Array.isArray(value.enum) && value.enum.length > 0) - .reduce((result: any, [key, value]: any) => { - // Transform the key using localisedValue function - const newKey: any = getLocalizedName(key, localizationMap); - result[newKey] = value.enum; - return result; - }, {}); - logger.info(`dropdowns to set ${JSON.stringify(dropdowns)}`) - request.body.dropdowns = dropdowns; - return dropdowns; -} - -function setHiddenColumns(request: any, schema: any, localizationMap?: { [key: string]: string }) { - // from schema.properties find the key whose value have value.hideColumn == true - const hiddenColumns = Object.entries(schema.properties).filter(([key, value]: any) => value.hideColumn == true).map(([key, value]: any) => getLocalizedName(key, localizationMap)); - logger.info(`Columns to hide ${JSON.stringify(hiddenColumns)}`); - request.body.hiddenColumns = hiddenColumns; -} - -async function getResourceDistributionStrategyTypes(request: any) { - const { RequestInfo = {} } = request?.body || {}; - const requestBody = { - RequestInfo, - MdmsCriteria: { - tenantId: request?.query?.tenantId, - schemaCode: "hcm-microplanning.ResourceDistributionStrategy" - } - }; - const url = config.host.mdmsV2 + config.paths.mdms_v2_search; - const response = await httpRequest(url, requestBody, undefined, undefined, undefined); - if (response?.mdms && Array.isArray(response?.mdms)) { - const resourceDistributionStrategyTypes = response?.mdms?.map((mdms: any) => mdms?.data?.resourceDistributionStrategyCode); - return resourceDistributionStrategyTypes; - } - else { - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during resource distribution strategy type search"); - } -} - -async function getSchemaBasedOnSource(request: any, isSourceMicroplan: boolean, resourceDistributionStrategy: string) { - const tenantId = request?.query?.tenantId; - let schema: any; - if (isSourceMicroplan) { - const resourceDistributionStrategyTypes = await getResourceDistributionStrategyTypes(request); - if (resourceDistributionStrategyTypes.includes(resourceDistributionStrategy)) { - schema = await callMdmsTypeSchema(request, tenantId, false, "facility", `MP-FACILITY-${resourceDistributionStrategy}`); - } - else { - throwError("CAMPAIGN", 500, "INVALID_RESOURCE_DISTRIBUTION_STRATEGY", `Invalid resource distribution strategy: ${resourceDistributionStrategy} ; Allowed resource distribution strategies: ${resourceDistributionStrategyTypes}`); - } - } else { - schema = await callMdmsTypeSchema(request, tenantId, false, "facility", "all"); - } - return schema; -} - async function createFacilitySheet(request: any, allFacilities: any[], localizationMap?: { [key: string]: string }) { - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const isSourceMicroplan = checkIfSourceIsMicroplan(responseFromCampaignSearch?.CampaignDetails?.[0]); - request.body.isSourceMicroplan = isSourceMicroplan; - let schema: any = await getSchemaBasedOnSource(request, isSourceMicroplan, responseFromCampaignSearch?.CampaignDetails?.[0]?.additionalDetails?.resourceDistributionStrategy); + const tenantId = request?.query?.tenantId; + const schema = await callMdmsTypeSchema(request, tenantId, "facility"); const keys = schema?.columns; - setDropdownFromSchema(request, schema, localizationMap); - setHiddenColumns(request, schema, localizationMap); const headers = ["HCM_ADMIN_CONSOLE_FACILITY_CODE", ...keys] - let localizedHeaders; - if (isSourceMicroplan) { - localizedHeaders = getLocalizedHeadersForMicroplan(responseFromCampaignSearch, headers, localizationMap); + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); - } - else { - localizedHeaders = getLocalizedHeaders(headers, localizationMap); - } const facilities = allFacilities.map((facility: any) => { return [ facility?.id, @@ -599,24 +467,17 @@ function setAndFormatHeaders(worksheet: any, mainHeader: any, headerSet: any) { } async function createReadMeSheet(request: any, workbook: any, mainHeader: any, localizationMap = {}) { - const isSourceMicroplan = await isMicroplanRequest(request); - let readMeConfig: any; - if (isSourceMicroplan) { - readMeConfig = await getReadMeConfigForMicroplan(request); - } - else { - readMeConfig = await getReadMeConfig(request); - } + const readMeConfig = await getReadMeConfig(request); const headerSet = new Set(); - const datas = readMeConfig.texts - .filter((text: any) => text?.inSheet) // Filter out texts with inSheet set to false - .flatMap((text: any) => { - const descriptions = text.descriptions.map((description: any) => { - return getLocalizedName(description.text, localizationMap); - }); - headerSet.add(getLocalizedName(text.header, localizationMap)); - return [getLocalizedName(text.header, localizationMap), ...descriptions, ""]; + + + const datas = readMeConfig.texts.flatMap((text: any) => { + const descriptions = text.descriptions.map((description: any) => { + return getLocalizedName(description.text, localizationMap); }); + headerSet.add(getLocalizedName(text.header, localizationMap)); + return [getLocalizedName(text.header, localizationMap), ...descriptions, "", "", "", ""]; + }); // Create the worksheet and add the main header const worksheet = workbook.addWorksheet(getLocalizedName("HCM_README_SHEETNAME", localizationMap)); @@ -664,21 +525,6 @@ function getLocalizedHeaders(headers: any, localizationMap?: { [key: string]: st return messages; } -function getLocalizedHeadersForMicroplan(responseFromCampaignSearch: any, headers: any, localizationMap?: { [key: string]: string }) { - - const projectType = responseFromCampaignSearch?.CampaignDetails?.[0]?.projectType; - - headers = headers.map((header: string) => { - if (header === 'HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN') { - return `${header}_${projectType}`; - } - return header; - }); - - const messages = headers.map((header: any) => (localizationMap ? localizationMap[header] || header : header)); - return messages; -} - function modifyRequestForLocalisation(request: any, tenantId: string) { @@ -731,7 +577,7 @@ function hideUniqueIdentifierColumn(sheet: any, column: any) { } -async function createFacilityAndBoundaryFile(facilitySheetData: any, boundarySheetData: any, request: any, localizationMap?: any, fileUrl?: any, schema?: any) { +async function createFacilityAndBoundaryFile(facilitySheetData: any, boundarySheetData: any, request: any, localizationMap?: any) { const workbook = getNewExcelWorkbook(); // Add facility sheet to the workbook @@ -745,99 +591,29 @@ async function createFacilityAndBoundaryFile(facilitySheetData: any, boundaryShe // Add facility sheet data const facilitySheet = workbook.addWorksheet(localizedFacilityTab); - addDataToSheet(request, facilitySheet, facilitySheetData, undefined, undefined, true, false, localizationMap, fileUrl, schema); + addDataToSheet(facilitySheet, facilitySheetData, undefined, undefined, true); hideUniqueIdentifierColumn(facilitySheet, createAndSearch?.["facility"]?.uniqueIdentifierColumn); changeFirstRowColumnColour(facilitySheet, 'E06666'); - let receivedDropdowns = request.body?.dropdowns; - logger.info("started adding dropdowns in facility", JSON.stringify(receivedDropdowns)) - - if (!receivedDropdowns || Object.keys(receivedDropdowns)?.length == 0) { - logger.info("No dropdowns found"); - receivedDropdowns = setDropdownFromSchema(request, schema, localizationMap); - logger.info("refetched drodowns", JSON.stringify(receivedDropdowns)) - } - await handledropdownthings(facilitySheet, receivedDropdowns); - await handleHiddenColumns(facilitySheet, request.body?.hiddenColumns); - // Add boundary sheet to the workbook const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - boundarySheetData = modifyBoundaryIfSourceMicroplan(boundarySheetData, request); - addDataToSheet(request, boundarySheet, boundarySheetData, 'F3842D', 30, false, true); + addDataToSheet(boundarySheet, boundarySheetData, 'F3842D', 30, false, true); // Create and upload the fileData at row const fileDetails = await createAndUploadFile(workbook, request); request.body.fileDetails = fileDetails; } -async function handledropdownthings(sheet: any, dropdowns: any) { - let dropdownColumnIndex = -1; - if (dropdowns) { - logger.info("Dropdowns provided:", dropdowns); - for (const key of Object.keys(dropdowns)) { - if (dropdowns[key]) { - logger.info(`Processing dropdown key: ${key} with values: ${dropdowns[key]}`); - const firstRow = sheet.getRow(1); - firstRow.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { - if (cell.value === key) { - dropdownColumnIndex = colNumber; - logger.info(`Found column index for dropdown "${key}": ${dropdownColumnIndex}`); - } - }); - - // If dropdown column index is found, set multi-select dropdown for subsequent rows - if (dropdownColumnIndex !== -1) { - logger.info(`Setting dropdown for column index: ${dropdownColumnIndex}`); - sheet.getColumn(dropdownColumnIndex).eachCell({ includeEmpty: true }, (cell: any, rowNumber: any) => { - if (rowNumber > 1) { - // Set dropdown list with no typing allowed - cell.dataValidation = { - type: 'list', - formulae: [`"${dropdowns[key].join(',')}"`], - showDropDown: true, - error: 'Please select a value from the dropdown list.', - errorStyle: 'stop', - showErrorMessage: true, - errorTitle: 'Invalid Entry' - }; - } - }); - } else { - logger.info(`Dropdown column index not found for key: ${key}`); - } - } - } - } else { - logger.info("No dropdowns provided."); - } -} -async function handleHiddenColumns(sheet: any, hiddenColumns: any) { - // logger.info(sheet) - logger.info("hiddenColumns", hiddenColumns); - if (hiddenColumns) { - for (const columnName of hiddenColumns) { - const firstRow = sheet.getRow(1); - let colIndex = -1; - firstRow.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { - if (cell.value === columnName) { - colIndex = colNumber; - } - if (colIndex !== -1) { - sheet.getColumn(colIndex).hidden = true - } - }); - } - } -} +// Helper function to add data to a sheet -async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: any, request: any, schema: any, localizationMap?: { [key: string]: string }, fileUrl?: any) { +async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: any, request: any, localizationMap?: { [key: string]: string }) { const workbook = getNewExcelWorkbook(); const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); const type = request?.query?.type; @@ -846,259 +622,84 @@ async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: await createReadMeSheet(request, workbook, localisedHeading, localizationMap); const userSheet = workbook.addWorksheet(localizedUserTab); - addDataToSheet(request, userSheet, userSheetData, undefined, undefined, true, false, localizationMap, fileUrl, schema); - hideUniqueIdentifierColumn(userSheet, createAndSearch?.["user"]?.uniqueIdentifierColumn); - - let receivedDropdowns = request.body?.dropdowns; - logger.info("started adding dropdowns in user", JSON.stringify(receivedDropdowns)) - - if (!receivedDropdowns || Object.keys(receivedDropdowns)?.length == 0) { - logger.info("No dropdowns found"); - receivedDropdowns = setDropdownFromSchema(request, schema, localizationMap); - logger.info("refetched drodowns", JSON.stringify(receivedDropdowns)) - } - await handledropdownthings(userSheet, receivedDropdowns); - await handleHiddenColumns(userSheet, request.body?.hiddenColumns); + addDataToSheet(userSheet, userSheetData, undefined, undefined, true); // Add boundary sheet to the workbook const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap) const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - addDataToSheet(request, boundarySheet, boundarySheetData, 'F3842D', 30, false, true); + addDataToSheet(boundarySheet, boundarySheetData, 'F3842D', 30, false, true); const fileDetails = await createAndUploadFile(workbook, request) request.body.fileDetails = fileDetails; } -async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, fileUrl?: any) { - const type = request?.query?.type || request?.body?.ResourceDetails?.type; - const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; +async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }) { // Get facility and boundary data logger.info("Generating facilities started"); const allFacilities = await getAllFacilities(tenantId, request.body); request.body.generatedResourceCount = allFacilities?.length; logger.info(`Facilities generation completed and found ${allFacilities?.length} facilities`); - let facilitySheetData: any; - const localizedFacilityTab = getLocalizedName(config?.facility?.facilityTab, localizationMap); - let schema: any; - if (fileUrl) { - /* fetch facility from processed file - and generate facility sheet data */ - schema = await callMdmsTypeSchema(request, tenantId, true, typeWithoutWith, "all"); - const processedFacilitySheetData = await getSheetData(fileUrl, localizedFacilityTab, false, undefined, localizationMap); - const modifiedProcessedFacilitySheetData = modifyProcessedSheetData(typeWithoutWith, processedFacilitySheetData, schema, localizationMap); - facilitySheetData = modifiedProcessedFacilitySheetData; - setDropdownFromSchema(request, schema, localizationMap); - } - else { - facilitySheetData = await createFacilitySheet(request, allFacilities, localizationMap); - } + const facilitySheetData: any = await createFacilitySheet(request, allFacilities, localizationMap); // request.body.Filters = { tenantId: tenantId, hierarchyType: request?.query?.hierarchyType, includeChildren: true } - if (filteredBoundary && filteredBoundary.length > 0) { - logger.info("proceed with the filtered boundary data") - await createFacilityAndBoundaryFile(facilitySheetData, filteredBoundary, request, localizationMap, fileUrl, schema); - } - else { - const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); - await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap, fileUrl, schema); - } + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap); } - -async function generateUserSheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, userData?: any, fileUrl?: any) { +async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }) { + const userData: any[] = []; const tenantId = request?.query?.tenantId; - const type = request?.query?.type || request?.body?.ResourceDetails?.type; - const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; - let schema: any; - const isUpdate = fileUrl ? true : false; - schema = await callMdmsTypeSchema(request, tenantId, isUpdate, typeWithoutWith); - setDropdownFromSchema(request, schema, localizationMap); + const schema = await callMdmsTypeSchema(request, tenantId, "user"); const headers = schema?.columns; const localizedHeaders = getLocalizedHeaders(headers, localizationMap); - const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); - let userSheetData: any; // const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); logger.info("Generated an empty user template"); - if (fileUrl) { - /* fetch facility from processed file - and generate facility sheet data */ - const processedUserSheetData = await getSheetData(fileUrl, localizedUserTab, false, undefined, localizationMap); - const modifiedProcessedUserSheetData = modifyProcessedSheetData(typeWithoutWith, processedUserSheetData, schema, localizationMap); - userSheetData = modifiedProcessedUserSheetData; - } - else { - userSheetData = await createExcelSheet(userData, localizedHeaders); - } - if (filteredBoundary && filteredBoundary.length > 0) { - logger.info("proceed with the filtered boundary data") - await createUserAndBoundaryFile(userSheetData, filteredBoundary, request, schema, localizationMap, fileUrl); - } - else { - const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); - await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, schema, localizationMap, fileUrl); - } -} - - -async function getCustomSheetData(request: any, type: any, sheetName: any) { - const { RequestInfo = {} } = request?.body || {}; - const requestBody = { - RequestInfo, - MdmsCriteria: { - tenantId: request?.query?.tenantId, - uniqueIdentifiers: [ - `${sheetName}.${type}` - ], - schemaCode: "HCM-ADMIN-CONSOLE.customSheetData" - } - }; - const url = config.host.mdmsV2 + config.paths.mdms_v2_search; - const header = { - ...defaultheader, - cachekey: `mdmsv2Seacrh${requestBody?.MdmsCriteria?.tenantId}${sheetName}${type}.${sheetName}${requestBody?.MdmsCriteria?.schemaCode}` - } - const response = await httpRequest(url, requestBody, undefined, undefined, undefined, header); - if (!response?.mdms?.[0]?.data) { - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during customSheet config search"); - } - return response?.mdms?.[0]?.data; -} - -function getConvertedSheetData(allRows: any) { - const headersSet = new Set(); - allRows.forEach((row: any) => { - Object.keys(row).forEach(header => headersSet.add(header)); - }); - const headers: any = Array.from(headersSet); - - // Map rows to include all headers, filling missing values with "" - const sheetData = allRows.map((row: any) => - headers.map((header: any) => row[header] || "") - ); - - sheetData.unshift(headers); - return sheetData; -} -async function makeCustomSheetData(request: any, type: any, sheetName: any, workbook: any, localizationMap: any) { - const data = await getCustomSheetData(request, type, sheetName); - const sheetNameAfterTranslation = getLocalizedName(sheetName, localizationMap); - const customSheet = workbook.addWorksheet(sheetNameAfterTranslation); - const allRows: any = [] - for (const rows of data?.data) { - const rowData: any = {} - for (const row of rows) { - rowData[getLocalizedName(row?.column, localizationMap)] = getLocalizedName(row?.value, localizationMap); - } - allRows.push(rowData); - } - const sheetData = getConvertedSheetData(allRows); - addDataToSheet(request, customSheet, sheetData, undefined, undefined); - customSheet.protect('passwordhere', { - selectLockedCells: true, - selectUnlockedCells: true - }); -} - -async function generateUserSheetForMicroPlan( - request: any, - rolesForMicroplan: string[], - userData?: any, - localizationMap?: any, - fileUrl?: any -) { - const { tenantId, type } = request?.query; - const schema = await callMdmsTypeSchema(request, tenantId, false, "user", "microplan"); - setDropdownFromSchema(request, schema, localizationMap); - const headers = schema?.columns; - const localizedHeaders = getLocalizedHeaders(headers, localizationMap); - - logger.info("Generated an empty user template"); - - const workbook = getNewExcelWorkbook(); - const userSheetData = await createExcelSheet(userData, localizedHeaders); // Create data only once - - // Create and add ReadMe sheet - const headingInSheet = headingMapping?.[type]; - const localizedHeading = getLocalizedName(headingInSheet, localizationMap); - await createReadMeSheet(request, workbook, localizedHeading, localizationMap); - - - await makeCustomSheetData(request, request?.query?.type, "USER_MICROPLAN_SHEET_ROLES", workbook, localizationMap); - - // Loop through the rolesForMicroplan array to create sheets for each role - for (const role of rolesForMicroplan) { - // Create a sheet for each role, using the role name as the sheet name - const userSheet: any = workbook.addWorksheet(role); - addDataToSheet(request, userSheet, userSheetData, undefined, undefined, true, false, localizationMap, fileUrl, schema); - await handledropdownthings(userSheet, request.body?.dropdowns); - await handleHiddenColumns(userSheet, request.body?.hiddenColumns); - } - - // Create and upload the workbook file - const fileDetails = await createAndUploadFile(workbook, request); - request.body.fileDetails = fileDetails; -} - - - - -async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, fileUrl?: any) { - const userData: any[] = []; - const tenantId = request?.query?.tenantId; - const isSourceMicroplan = await isMicroplanRequest(request); - if (isSourceMicroplan) { - const rolesForMicroplan = await getRolesForMicroplan(tenantId, localizationMap); - await generateUserSheetForMicroPlan(request, rolesForMicroplan, userData, localizationMap, fileUrl); - } - else { - await generateUserSheet(request, localizationMap, filteredBoundary, userData, fileUrl); - } + const userSheetData = await createExcelSheet(userData, localizedHeaders); + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, localizationMap); } - -async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, fileUrl?: string) { +async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }) { const { type, tenantId } = request.query if (type == "facilityWithBoundary") { - await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap, filteredBoundary, fileUrl); + await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap); } if (type == "userWithBoundary") { - await generateUserAndBoundarySheet(request, localizationMap, filteredBoundary, fileUrl); + await generateUserAndBoundarySheet(request, localizationMap); } } -async function processGenerateForNew(request: any, generatedResource: any, newEntryResponse: any, enableCaching = false, filteredBoundary?: any) { +async function processGenerateForNew(request: any, generatedResource: any, newEntryResponse: any) { request.body.generatedResource = newEntryResponse; - logger.info("Generate flow :: processing new request"); - await fullProcessFlowForNewEntry(newEntryResponse, generatedResource, request, enableCaching, filteredBoundary); + fullProcessFlowForNewEntry(newEntryResponse, generatedResource, request); return request.body.generatedResource; } -async function handleGenerateError(newEntryResponse: any, generatedResource: any, error: any) { +function handleGenerateError(newEntryResponse: any, generatedResource: any, error: any) { newEntryResponse.map((item: any) => { item.status = generatedResourceStatuses.failed, item.additionalDetails = { - ...item.additionalDetails, - error: { + ...item.additionalDetails, error: { status: error.status, code: error.code, description: error.description, message: error.message - } + } || String(error) } }) generatedResource = { generatedResource: newEntryResponse }; logger.error(String(error)); - await produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); + produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); } -async function updateAndPersistGenerateRequest(newEntryResponse: any, oldEntryResponse: any, responseData: any, request: any, enableCaching = false, filteredBoundary?: any) { +async function updateAndPersistGenerateRequest(newEntryResponse: any, oldEntryResponse: any, responseData: any, request: any) { const { forceUpdate } = request.query; const forceUpdateBool: boolean = forceUpdate === 'true'; let generatedResource: any; if (forceUpdateBool && responseData.length > 0) { generatedResource = { generatedResource: oldEntryResponse }; // send message to update topic - await produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); + produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); request.body.generatedResource = oldEntryResponse; } if (responseData.length === 0 || forceUpdateBool) { - processGenerateForNew(request, generatedResource, newEntryResponse, enableCaching, filteredBoundary) + processGenerateForNew(request, generatedResource, newEntryResponse) } else { request.body.generatedResource = responseData @@ -1107,7 +708,7 @@ async function updateAndPersistGenerateRequest(newEntryResponse: any, oldEntryRe /* */ -async function processGenerate(request: any, enableCaching = false, filteredBoundary?: any) { +async function processGenerate(request: any) { // fetch the data from db to check any request already exists const responseData = await searchGeneratedResources(request); // modify response from db @@ -1117,7 +718,7 @@ async function processGenerate(request: any, enableCaching = false, filteredBoun // make old data status as expired const oldEntryResponse = await updateExistingResourceExpired(modifiedResponse, request); // generate data - await updateAndPersistGenerateRequest(newEntryResponse, oldEntryResponse, responseData, request, enableCaching, filteredBoundary); + await updateAndPersistGenerateRequest(newEntryResponse, oldEntryResponse, responseData, request); } /* TODO add comments @nitish-egov @@ -1132,18 +733,14 @@ async function enrichResourceDetails(request: any) { else { request.body.ResourceDetails.status = resourceDataStatuses.started } - request.body.ResourceDetails.auditDetails = { createdBy: request?.body?.RequestInfo?.userInfo?.uuid, createdTime: Date.now(), lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, lastModifiedTime: Date.now() } - if (request.body.ResourceDetails.type === 'boundary') { - request.body.ResourceDetails.campaignId = null; - } const persistMessage: any = { ResourceDetails: request.body.ResourceDetails }; - await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC); + produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC); } function getFacilityIds(data: any) { @@ -1222,7 +819,9 @@ function modifyBoundaryData(boundaryData: any[], localizationMap?: any) { return [withBoundaryCode, withoutBoundaryCode]; } -async function getDataFromSheetFromNormalCampaign(type: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, optionalSheetName?: any, localizationMap?: { [key: string]: string }) { + +async function getDataFromSheet(request: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, optionalSheetName?: any, localizationMap?: { [key: string]: string }) { + const type = request?.body?.ResourceDetails?.type; const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); if (!fileResponse?.fileStoreIds?.[0]?.url) { throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); @@ -1231,35 +830,17 @@ async function getDataFromSheetFromNormalCampaign(type: any, fileStoreId: any, t return await getTargetSheetData(fileResponse?.fileStoreIds?.[0]?.url, true, true, localizationMap); } return await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, createAndSearchConfig?.parseArrayConfig?.sheetName || optionalSheetName, true, createAndSearchConfig, localizationMap) - -} - - -async function getDataFromSheet(request: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, optionalSheetName?: any, localizationMap?: { [key: string]: string }) { - const isSourceMicroplan = request?.body?.ResourceDetails?.additionalDetails?.source == "microplan"; - const type = request?.body?.ResourceDetails?.type; - if (isSourceMicroplan) { - if (type == 'user') { - return await getUserDataFromMicroplanSheet(request, fileStoreId, tenantId, createAndSearchConfig, localizationMap); - } - else { - return await getDataFromSheetFromNormalCampaign(type, fileStoreId, tenantId, createAndSearchConfig, optionalSheetName, localizationMap); - } - } - else { - return await getDataFromSheetFromNormalCampaign(type, fileStoreId, tenantId, createAndSearchConfig, optionalSheetName, localizationMap); - } } async function getBoundaryRelationshipData(request: any, params: any) { - logger.info("Boundary relationship search initiated"); + logger.info("Boundary relationship search initiated") const url = `${config.host.boundaryHost}${config.paths.boundaryRelationship}`; const header = { ...defaultheader, - // cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, } const boundaryRelationshipResponse = await httpRequest(url, request.body, params, undefined, undefined, header); - logger.info("Boundary relationship search response received"); + logger.info("Boundary relationship search response received") return boundaryRelationshipResponse?.TenantBoundary?.[0]?.boundary; } @@ -1274,15 +855,13 @@ async function getDataSheetReady(boundaryData: any, request: any, localizationMa const hierarchy = await getHierarchy(request, request?.query?.tenantId, request?.query?.hierarchyType); const startIndex = boundaryType ? hierarchy.indexOf(boundaryType) : -1; const reducedHierarchy = startIndex !== -1 ? hierarchy.slice(startIndex) : hierarchy; - const modifiedReducedHierarchy = getLocalizedHeaders(reducedHierarchy.map(ele => `${request?.query?.hierarchyType}_${ele}`.toUpperCase()), localizationMap); + const modifiedReducedHierarchy = reducedHierarchy.map(ele => `${request?.query?.hierarchyType}_${ele}`.toUpperCase()) // get Campaign Details from Campaign Search Api var configurableColumnHeadersBasedOnCampaignType: any[] = [] if (type == "boundary") { configurableColumnHeadersBasedOnCampaignType = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); } - if (type == "boundaryManagement" || type == "boundaryGeometryManagement") { - configurableColumnHeadersBasedOnCampaignType = await getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement(request, localizationMap); - } + const headers = (type !== "facilityWithBoundary" && type !== "userWithBoundary") ? [ ...modifiedReducedHierarchy, @@ -1293,11 +872,9 @@ async function getDataSheetReady(boundaryData: any, request: any, localizationMa getBoundaryColumnName() ]; const localizedHeaders = getLocalizedHeaders(headers, localizationMap); - var boundaryCodeList: any[] = []; - var data = boundaryList.map(boundary => { + const data = boundaryList.map(boundary => { const boundaryParts = boundary.split(','); const boundaryCode = boundaryParts[boundaryParts.length - 1]; - boundaryCodeList.push(boundaryCode); const rowData = boundaryParts.concat(Array(Math.max(0, reducedHierarchy.length - boundaryParts.length)).fill('')); // localize the boundary codes const mappedRowData = rowData.map((cell: any, index: number) => @@ -1307,19 +884,6 @@ async function getDataSheetReady(boundaryData: any, request: any, localizationMa mappedRowData[boundaryCodeIndex] = boundaryCode; return mappedRowData; }); - if (type == "boundaryManagement") { - logger.info("Processing data for boundaryManagement type") - const latLongBoundaryMap = await getLatLongMapForBoundaryCodes(request, boundaryCodeList); - for (let d of data) { - const boundaryCode = d[d.length - 1]; // Assume last element is the boundary code - - if (latLongBoundaryMap[boundaryCode]) { - const [latitude = null, longitude = null] = latLongBoundaryMap[boundaryCode]; // Destructure lat/long - d.push(latitude); // Append latitude - d.push(longitude); // Append longitude - } - } - } const sheetRowCount = data.length; if (type != "facilityWithBoundary") { request.body.generatedResourceCount = sheetRowCount; @@ -1360,38 +924,25 @@ function modifyDataBasedOnDifferentTab(boundaryData: any, differentTabsBasedOnLe } -async function getLocalizedMessagesHandler(request: any, tenantId: any, module = config.localisation.localizationModule, overrideCache = false) { +async function getLocalizedMessagesHandler(request: any, tenantId: any, module = config.localisation.localizationModule) { const localisationcontroller = Localisation.getInstance(); const locale = getLocaleFromRequest(request); - const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId, overrideCache); - return localizationResponse; -} - -async function getLocalizedMessagesHandlerViaRequestInfo(RequestInfo: any, tenantId: any, module = config.localisation.localizationModule) { - const localisationcontroller = Localisation.getInstance(); - const locale = getLocaleFromRequestInfo(RequestInfo); const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId); return localizationResponse; } -async function translateSchema( - schema: any, - localizationMap?: { [key: string]: string }) { +async function translateSchema(schema: any, localizationMap?: { [key: string]: string }) { const translatedSchema = { ...schema, properties: Object.entries(schema?.properties || {}).reduce((acc, [key, value]) => { const localizedMessage = getLocalizedName(key, localizationMap); acc[localizedMessage] = value; return acc; - }, {} as { [key: string]: any }), - - required: (schema?.required || []) - .map((key: string) => getLocalizedName(key, localizationMap)), - - unique: (schema?.unique || []) - .map((key: string) => getLocalizedName(key, localizationMap)) + }, {} as { [key: string]: any }), // Initialize with the correct type + required: (schema?.required || []).map((key: string) => getLocalizedName(key, localizationMap)), + unique: (schema?.unique || []).map((key: string) => getLocalizedName(key, localizationMap)) }; return translatedSchema; @@ -1415,7 +966,7 @@ function getDifferentDistrictTabs(boundaryData: any, differentTabsBasedOnLevel: const rowData = Object.values(data); const districtValue = data[differentTabsBasedOnLevel]; const districtIndex = districtValue !== '' ? rowData.indexOf(districtValue) : -1; - + // replaced '_' with '#' to avoid errors caused by underscores in boundary codes. if (districtIndex != -1) { const districtLevelRow = rowData.slice(0, districtIndex + 1); const districtKey = districtLevelRow.join('#'); @@ -1432,78 +983,25 @@ function getDifferentDistrictTabs(boundaryData: any, differentTabsBasedOnLevel: } -async function getConfigurableColumnHeadersFromSchemaForTargetSheet(request: any, hierarchy: any, boundaryData: any, differentTabsBasedOnLevel: any, campaignObject: any, localizationMap?: any) { +async function getConfigurableColumnHeadersFromSchemaForTargetSheet(request: any, hierarchy: any, boundaryData: any, differentTabsBasedOnLevel: any, localizationMap?: any) { const districtIndex = hierarchy.indexOf(differentTabsBasedOnLevel); - let headers: any; - const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); - if (isSourceMicroplan) { - logger.info(`Source is Microplan.`); - headers = getLocalizedHeaders(hierarchy, localizationMap); - } - else { - headers = getLocalizedHeaders(hierarchy.slice(districtIndex), localizationMap); - } - const headerColumnsAfterHierarchy = await generateDynamicTargetHeaders(request, campaignObject, localizationMap); + var headers = getLocalizedHeaders(hierarchy.slice(districtIndex), localizationMap); + + const headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request); const localizedHeadersAfterHierarchy = getLocalizedHeaders(headerColumnsAfterHierarchy, localizationMap); - headers = [...headers, getLocalizedName(config?.boundary?.boundaryCode, localizationMap), ...localizedHeadersAfterHierarchy] + headers = [...headers, ...localizedHeadersAfterHierarchy] return getLocalizedHeaders(headers, localizationMap); } async function getMdmsDataBasedOnCampaignType(request: any, localizationMap?: any) { const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - let campaignType = campaignObject.projectType; - const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); - campaignType = (isSourceMicroplan) ? `${config?.prefixForMicroplanCampaigns}-${campaignType}` : campaignType; - const mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, false, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) + const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; + const mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) return mdmsResponse; } -function appendProjectTypeToCapacity(schema: any, projectType: string): any { - const updatedSchema = JSON.parse(JSON.stringify(schema)); // Deep clone the schema - - const capacityKey = 'HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN'; - const newCapacityKey = `${capacityKey}_${projectType}`; - - // Update properties - if (updatedSchema.properties[capacityKey]) { - updatedSchema.properties[newCapacityKey] = { - ...updatedSchema.properties[capacityKey], - name: `${updatedSchema.properties[capacityKey].name}_${projectType}` - }; - delete updatedSchema.properties[capacityKey]; - } - - // Update required - updatedSchema.required = updatedSchema.required.map((item: string) => - item === capacityKey ? newCapacityKey : item - ); - - // Update columns - updatedSchema.columns = updatedSchema.columns.map((item: string) => - item === capacityKey ? newCapacityKey : item - ); - - // Update unique - updatedSchema.unique = updatedSchema.unique.map((item: string) => - item === capacityKey ? newCapacityKey : item - ); - - // Update errorMessage - if (updatedSchema.errorMessage[capacityKey]) { - updatedSchema.errorMessage[newCapacityKey] = updatedSchema.errorMessage[capacityKey]; - delete updatedSchema.errorMessage[capacityKey]; - } - - // Update columnsNotToBeFreezed - updatedSchema.columnsNotToBeFreezed = updatedSchema.columnsNotToBeFreezed.map((item: string) => - item === capacityKey ? newCapacityKey : item - ); - - return updatedSchema; -} export { @@ -1550,10 +1048,7 @@ export { changeFirstRowColumnColour, getConfigurableColumnHeadersFromSchemaForTargetSheet, createBoundaryDataMainSheet, - getMdmsDataBasedOnCampaignType, - shutdownGracefully, - appendProjectTypeToCapacity, - getLocalizedMessagesHandlerViaRequestInfo, - createFacilityAndBoundaryFile, - hideUniqueIdentifierColumn + getMdmsDataBasedOnCampaignType }; + + diff --git a/health-services/project-factory/src/server/utils/localisationUtils.ts b/health-services/project-factory/src/server/utils/localisationUtils.ts index 3d5585947ef..0b1bd4804be 100644 --- a/health-services/project-factory/src/server/utils/localisationUtils.ts +++ b/health-services/project-factory/src/server/utils/localisationUtils.ts @@ -6,15 +6,7 @@ export const getLocaleFromRequest = (request: any) => { const msgId = request?.body?.RequestInfo?.msgId; // Split msgId by '|' delimiter and get the second part (index 1) // If splitting fails or no second part is found, use default locale from config - return msgId?.split("|")?.[1] || config?.localisation?.defaultLocale; -}; - -export const getLocaleFromRequestInfo = (RequestInfo: any) => { - // Extract msgId from request body - const msgId = RequestInfo?.msgId; - // Split msgId by '|' delimiter and get the second part (index 1) - // If splitting fails or no second part is found, use default locale from config - return msgId?.split("|")?.[1] || config?.localisation?.defaultLocale; + return msgId.split("|")?.[1] || config?.localisation?.defaultLocale; }; // Function to generate localisation module name based on hierarchy type @@ -30,17 +22,17 @@ export const getLocalisationModuleName = (hierarchyType: any) => { * @returns The transformed locale string. */ export const getTransformedLocale = (label: string) => { - // Trim leading and trailing whitespace from the label - label = label?.trim(); - // If label is not empty, convert to uppercase and replace special characters with underscores - return label && label.toUpperCase().replace(/[.:-\s\/]/g, "_"); -}; + // Trim leading and trailing whitespace from the label + label = label?.trim(); + // If label is not empty, convert to uppercase and replace special characters with underscores + return label && label.toUpperCase().replace(/[.:-\s\/]/g, "_"); + }; -export const convertLocalisationResponseToMap = (messages: any = []) => { - const localizationMap: any = {}; - messages.forEach((message: any) => { - localizationMap[message.code] = message.message; - }); - return localizationMap; -} \ No newline at end of file + export const convertLocalisationResponseToMap=(messages:any=[])=>{ + const localizationMap: any = {}; + messages.forEach((message: any) => { + localizationMap[message.code] = message.message; + }); + return localizationMap; + } \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/logger/index.ts b/health-services/project-factory/src/server/utils/logger/index.ts index 2e43c0011bf..f2cad55890b 100644 --- a/health-services/project-factory/src/server/utils/logger/index.ts +++ b/health-services/project-factory/src/server/utils/logger/index.ts @@ -25,17 +25,8 @@ export { logger }; const DEFAULT_LOG_MESSAGE_COUNT = config.app.debugLogCharLimit; -export const getFormattedStringForDebug = (obj: any): string => { - try { - const convertedMessage = JSON.stringify(obj); - return convertedMessage.slice(0, DEFAULT_LOG_MESSAGE_COUNT) + - (convertedMessage.length > DEFAULT_LOG_MESSAGE_COUNT ? "\n ---more" : ""); - } catch (error : any ) { - if (error instanceof RangeError && error.message.includes("Invalid string length")) { - logger.error("The object is too big to convert into a string."); - } else { - logger.error(`An unexpected error occurred while formatting the object into a string : ${error?.message}`); - } - return "Error: Unable to format object for debug."; - } -}; +export const getFormattedStringForDebug = (obj: any) => { + const convertedMessage=JSON.stringify(obj); + return convertedMessage?.slice(0, DEFAULT_LOG_MESSAGE_COUNT) + + (convertedMessage?.length > DEFAULT_LOG_MESSAGE_COUNT ? "\n ---more" : ""); +} diff --git a/health-services/project-factory/src/server/utils/microplanIntergration.ts b/health-services/project-factory/src/server/utils/microplanIntergration.ts deleted file mode 100644 index 15f0d5713b8..00000000000 --- a/health-services/project-factory/src/server/utils/microplanIntergration.ts +++ /dev/null @@ -1,985 +0,0 @@ -import { - callMdmsTypeSchema, - createAndUploadFile, - searchMDMS, -} from "../api/genericApis"; -import { getFormattedStringForDebug, logger } from "./logger"; - -import { - searchProjectTypeCampaignService, - updateProjectTypeCampaignService, -} from "../service/campaignManageService"; -import { - searchPlan, - searchPlanCensus, - searchPlanFacility, -} from "../api/microplanApis"; -import { - createAndPollForCompletion, - getTheGeneratedResource, -} from "./pollUtils"; -import { getExcelWorkbookFromFileURL } from "./excelUtils"; -import { - fetchFileFromFilestore, - searchBoundaryRelationshipData, - searchMDMSDataViaV1Api, -} from "../api/coreApis"; -import { getLocalizedName } from "./campaignUtils"; -import config from "../config"; -import { replicateRequest, throwError } from "./genericUtils"; -import { MDMSModels } from "../models"; -/** - * Adds data rows to the provided worksheet. - * @param worksheet The worksheet to which the data should be added. - * @param data Array of data rows to add. - */ -export async function addDataToWorksheet(worksheet: any, data: string[][]) { - data.forEach((row) => { - worksheet.addRow(row); - }); - - // Optionally, you can apply styles or adjust column widths - worksheet.columns.forEach((column: any) => { - column.width = 20; // Adjust column width to fit content - }); -} - -/** - * Updates existing rows in a worksheet with the given data, starting from row 2. - * @param worksheet The worksheet to update. - * @param data Array of data rows to insert. - */ -function updateWorksheetRows(worksheet: any, data: string[][]) { - data.forEach((rowData, index) => { - const rowNumber = 2 + index; // Start updating from row 2 - const row = worksheet.getRow(rowNumber); - - // Set values for each column in the row - rowData.forEach((cellValue, colIndex) => { - row.getCell(colIndex + 1).value = cellValue; // Column index starts at 1 - }); - - row.commit(); // Commit changes to the row - }); -} - -const getPlanFacilityMapByFacilityId = (planFacilityArray: any = []) => { - logger.info( - `filtered the plan facility response to have only facility which has only service boundarires` - ); - return planFacilityArray - ?.filter( - (planFacilityObj: any) => planFacilityObj?.serviceBoundaries?.length > 0 - ) - ?.reduce((acc: any, curr: any) => { - acc[curr?.facilityId] = curr; - return acc; - }, {}); -}; -const getRolesAndCount = (resources = [], userRoleMapping: any) => { - const USER_ROLE_MAP: any = {}; - - // Iterate through the userRoleMapping to determine rules for roles - userRoleMapping?.user?.forEach((mapping: any) => { - const { to, from, filter } = mapping; - - resources?.forEach((resource: any) => { - // Apply filter logic ensuring all criteria in `from` must match - const match = from.every((criteria: string) => - filter === "includes" - ? resource?.resourceType?.includes(criteria) - : resource?.resourceType === criteria - ); - - if (match) { - // Log the resource information - logger.info( - `filtered ${filter.toUpperCase()}: ${resource?.resourceType} :: ${ - resource?.estimatedNumber - }` - ); - - // Map roles based on the "to" field - USER_ROLE_MAP[to] = resource?.estimatedNumber; - } - }); - }); - - logger.info("Completed user role & boundary map"); - logger.info(`Map USER_ROLE_MAP ${getFormattedStringForDebug(USER_ROLE_MAP)}`); - - return { USER_ROLE_MAP }; -}; - -const getUserRoleMapWithBoundaryCode = ( - planFacilityArray: any = [], - userRoleMapping: any -) => { - return planFacilityArray?.reduce((acc: any, curr: any) => { - acc[curr?.locality] = { - // ...curr, - ...getRolesAndCount( - curr?.resources?.filter( - (resource: any) => resource?.estimatedNumber > 0 - ), - userRoleMapping - ), - }; - return acc; - }, {}); -}; - -function consolidateUserRoles( - userBoundaryMap: any, - boundaryiwthchildrednMap: any -) { - const result: any = {}; - - // Iterate through all parent boundaries - for (const parentBoundary in boundaryiwthchildrednMap) { - const children = boundaryiwthchildrednMap[parentBoundary]; - const consolidatedRoles: any = {}; - - // Process each child boundary - children.forEach((child: any) => { - const childCode = child.code; - const userRoles = userBoundaryMap[childCode]?.USER_ROLE_MAP || {}; - - // Aggregate roles for the parent boundary - for (const role in userRoles) { - if (!consolidatedRoles[role]) { - consolidatedRoles[role] = 0; - } - consolidatedRoles[role] += userRoles[role]; - } - }); - - // Attach consolidated roles to the parent boundary - result[parentBoundary] = { - parentBoundary, - children, - consolidatedRoles, - }; - } - - return result; -} - -// // Example Usage -// const consolidatedData = consolidateUserRoles(userBoundaryMap, boundaryiwthchildrednMap); -// console.log(JSON.stringify(consolidatedData, null, 2)); - -const getPlanCensusMapByBoundaryCode = (censusArray: any = []) => { - return censusArray?.reduce((acc: any, curr: any) => { - acc[curr?.boundaryCode] = curr; - return acc; - }, {}); -}; - -export const fetchFacilityData = async (request: any, localizationMap: any) => { - const { tenantId, planConfigurationId, campaignId } = - request.body.MicroplanDetails; - logger.info( - `doing the facility data fetch for planConfigurationId: ${planConfigurationId} and campaignId: ${campaignId} ` - ); - const facilityAdminSchema = await callMdmsTypeSchema( - request, - tenantId, - true, - "facility" - ); - const localizedHeadersMap = getLocalizedHeadersMapForFacility( - facilityAdminSchema.descriptionToFieldMap, - localizationMap - ); - const planFacilityResponse = await searchPlanFacility( - planConfigurationId, - tenantId - ); - logger.info(`got the facility mapping from the plan facility api`); - - const facilityBoundaryMap = - getPlanFacilityMapByFacilityId(planFacilityResponse); - logger.debug( - `created facilityBoundaryMap :${getFormattedStringForDebug( - facilityBoundaryMap - )}` - ); - - const generatedFacilityTemplateFileStoreId = await getTheGeneratedResource( - campaignId, - tenantId, - "facilityWithBoundary", - request.body.CampaignDetails?.hierarchyType - ); - logger.debug( - `downloadresponse fetchFacilityData ${getFormattedStringForDebug( - generatedFacilityTemplateFileStoreId - )}` - ); - const fileUrl = await fetchFileFromFilestore( - generatedFacilityTemplateFileStoreId, - tenantId - ); - logger.debug( - `downloadresponse fileUrl ${getFormattedStringForDebug(fileUrl)}` - ); - const workbook = await getExcelWorkbookFromFileURL( - fileUrl, - getLocalizedName(config?.facility?.facilityTab, localizationMap) - ); - logger.info(`workbook created for facility`); - - const updatedWorksheet = await findAndChangeFacilityData( - workbook.getWorksheet( - getLocalizedName(config?.facility?.facilityTab, localizationMap) - ), - facilityBoundaryMap, - localizedHeadersMap - ); - logger.info( - `workbook updated for facility with the data received from microplan` - ); - - const responseData = - updatedWorksheet && (await createAndUploadFile(workbook, request)); - logger.info( - "facility File updated successfully:" + JSON.stringify(responseData) - ); - if (responseData?.[0]?.fileStoreId) { - logger.info( - "facility File updated successfully:" + - JSON.stringify( - responseData?.[0]?.fileStoreId + " for campaignid : " + campaignId - ) - ); - } else { - throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); - } - - const polledResponseOfDataCreate = await validateSheet( - request, - tenantId, - "facility", - responseData?.[0]?.fileStoreId, - campaignId, - request.body.CampaignDetails.hierarchyType - ); - if ( - Array.isArray(polledResponseOfDataCreate) && - polledResponseOfDataCreate.length > 0 - ) { - await updateCampaignDetailsAfterSearch( - request, - polledResponseOfDataCreate?.[0], - "facility" - ); - logger.info( - `updated the resources of facility resource id ${polledResponseOfDataCreate?.[0]?.id}` - ); - } - logger.info( - `updated the resources of facility for campaignid : ${campaignId} and planid: ${planConfigurationId} ` - ); -}; - -function getLocalizedHeadersMapForFacility( - descriptionToFieldMap: Record, - localizationMap: any -) { - for (const [key, value] of Object.entries(descriptionToFieldMap)) { - descriptionToFieldMap[key] = getLocalizedName(value, localizationMap); - } - return descriptionToFieldMap; -} - -export const fetchTargetData = async (request: any, localizationMap: any) => { - const { tenantId, planConfigurationId, campaignId } = - request.body.MicroplanDetails; - logger.info( - `doing the target data fetch for planConfigurationId: ${planConfigurationId} and campaignId: ${campaignId} ` - ); - - const { projectType } = request.body.CampaignDetails; - const campaignType = "Target-" + projectType; - const userRoleMapping = await fetchUserRoleMappingFromMDMS(tenantId); - logger.info("received mdms data for target column mapping"); - logger.debug( - `target column mapping ${getFormattedStringForDebug(userRoleMapping)}` - ); - const planCensusResponse = await searchPlanCensus( - planConfigurationId, - tenantId, - getBoundariesFromCampaign(request.body.CampaignDetails)?.length - ); - logger.info(`got the target mapping from the census api`); - - const targetBoundaryMap = getPlanCensusMapByBoundaryCode(planCensusResponse); - logger.debug( - `created targetBoundaryMap :${getFormattedStringForDebug( - targetBoundaryMap - )}` - ); - - const generatedTargetTemplateFileStoreId = await getTheGeneratedResource( - campaignId, - tenantId, - "boundary", - request.body.CampaignDetails?.hierarchyType - ); - logger.debug( - `downloadresponse target ${getFormattedStringForDebug( - generatedTargetTemplateFileStoreId - )}` - ); - const fileUrl = await fetchFileFromFilestore( - generatedTargetTemplateFileStoreId, - tenantId - ); - logger.debug( - `downloadresponse target ${getFormattedStringForDebug(fileUrl)}` - ); - - const workbook = await getExcelWorkbookFromFileURL(fileUrl); - logger.info(`workbook created for target`); - - await workbook.worksheets.forEach(async (worksheet) => { - logger.info(`Processing worksheet: ${worksheet.name}`); - logger.info(`skipping processing worksheet: ${getLocalizedName(config?.boundary?.boundaryTab, localizationMap)} and ${getLocalizedName(config?.values?.readMeTab, localizationMap)} `); - - if ( - worksheet.name !== - getLocalizedName(config?.boundary?.boundaryTab, localizationMap) && - worksheet.name !== - getLocalizedName(config?.values?.readMeTab, localizationMap) - ) { - // harcoded to be changed - // Iterate over rows (skip the header row) - await findAndChangeTargetData( - worksheet, - targetBoundaryMap, - userRoleMapping[campaignType], - localizationMap - ); - } - }); - logger.info( - `workbook updated for target with the data received from microplan` - ); - - const responseData = await createAndUploadFile(workbook, request); - - logger.info( - "Target File updated successfully:" + JSON.stringify(responseData) - ); - if (responseData?.[0]?.fileStoreId) { - logger.info( - "Target File updated successfully:" + - JSON.stringify( - responseData?.[0]?.fileStoreId + " for campaignid : " + campaignId - ) - ); - } else { - throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); - } - const polledResponseOfDataCreate = await validateSheet( - request, - tenantId, - "boundaryWithTarget", - responseData?.[0]?.fileStoreId, - campaignId, - request.body.CampaignDetails.hierarchyType - ); - - if ( - Array.isArray(polledResponseOfDataCreate) && - polledResponseOfDataCreate.length > 0 - ) { - await updateCampaignDetailsAfterSearch( - request, - polledResponseOfDataCreate?.[0], - "boundaryWithTarget" - ); - logger.info( - `updated the resources of facility resource id ${polledResponseOfDataCreate?.[0]?.id}` - ); - } - logger.info( - `updated the resources of target for campaignid : ${campaignId} and planid: ${planConfigurationId} ` - ); -}; - -function findAndChangeUserData(worksheet: any, mappingData: any) { - logger.info( - `Received for facility mapping, enitity count : ${ - Object.keys(mappingData)?.length - }` - ); - logger.debug(`${getFormattedStringForDebug(mappingData)}, "mappingData user`); - // column no is // harcoded to be changed - const mappedData: any = {}; - - const dataRows: any = []; - Object.keys(mappingData).map((key) => { - const roles = Object.keys(mappingData[key].consolidatedRoles); - roles.map((role) => { - for (let i = 0; i < mappingData[key].consolidatedRoles?.[role]; i++) { - dataRows.push(["", "", role, "Permanent", key, "Active"]); - } - }); - }); - logger.debug( - `${getFormattedStringForDebug(dataRows)},"dataRows to be pushed` - ); - updateWorksheetRows(worksheet, dataRows); - - logger.info( - `Updated the boundary & active/inactive status information in facility received from the microplan` - ); - logger.info( - `mapping completed for facility enitity count : ${ - Object.keys(mappedData)?.length - }` - ); - logger.info( - `mapping not found for facility entity count : ${ - Object.keys(mappingData)?.length - Object.keys(mappedData)?.length - }` - ); - return worksheet; -} - -function findAndChangeFacilityData( - worksheet: any, - mappingData: Record< - string, - { - additionalDetails: any; - serviceBoundaries: string[]; - } - >, - headersMap: Record -) { - let facilityCodeIndex: number = 1; - let boundaryCodeIndex: number = 6; - let facilityUsageIndex: number = 7; - let headerValues: any = []; - - const mappedData: Record = {}; - const missingFacilities: string[] = []; - - // Iterate through each row in the worksheet - worksheet.eachRow((row: any, rowIndex: number) => { - if (rowIndex === 1) { - headerValues = row.values; - facilityCodeIndex = headerValues.indexOf("Facility Code"); - boundaryCodeIndex = headerValues.indexOf(headersMap["Boundary Code"]); - facilityUsageIndex = headerValues.indexOf(headersMap["Facility usage"]); - return; - } - - const facilityCode = row.getCell(facilityCodeIndex).value; - if (facilityCode && mappingData[facilityCode]) { - const facilityDetails = mappingData[facilityCode]; - row.getCell(boundaryCodeIndex).value = - facilityDetails.serviceBoundaries.join(",") || ""; - row.getCell(facilityUsageIndex).value = "Active"; - mappedData[facilityCode] = true; - } else { - row.getCell(boundaryCodeIndex).value = ""; - row.getCell(facilityUsageIndex).value = "Inactive"; - } - }); - - // Handle missing facilities - for (const [facilityCode, facilityDetails] of Object.entries(mappingData)) { - if (!mappedData[facilityCode]) { - missingFacilities.push(facilityCode); - - // Find the first empty row in the sheet - let emptyRowIndex = worksheet.rowCount + 1; // Default to the next available row - for (let i = 1; i <= worksheet.rowCount; i++) { - const row = worksheet.getRow(i); - if (!row.getCell(1).value) { // Assuming column 1 is used to determine emptiness - emptyRowIndex = i; - break; - } - } - - const newRow = worksheet.getRow(emptyRowIndex); - - // Assign values to the identified empty row - newRow.getCell(facilityCodeIndex).value = facilityCode; - newRow.getCell(headerValues.indexOf(headersMap["Facility Name"])).value = - facilityDetails?.additionalDetails?.facilityName; - newRow.getCell(headerValues.indexOf(headersMap["Facility type"])).value = - facilityDetails?.additionalDetails?.facilityType; - newRow.getCell( - headerValues.indexOf(headersMap["Facility status"]) - ).value = facilityDetails?.additionalDetails?.facilityStatus; - newRow.getCell(headerValues.indexOf(headersMap["Capacity"])).value = - facilityDetails?.additionalDetails?.capacity; - newRow.getCell(boundaryCodeIndex).value = - facilityDetails.serviceBoundaries.join(",") || ""; - newRow.getCell(facilityUsageIndex).value = "Active"; - - newRow.commit(); // Save the changes to the row - } - } - - logger.info( - `Updated the boundary & active/inactive status information in facility received from the microplan` - ); - logger.info( - `mapping completed for facility enitity count : ${ - Object.keys(mappedData)?.length - }` - ); - - return worksheet; -} - -function getHeaderIndex( - headers: any, - headerName: string, - localizationMap: any -) { - return headers.indexOf( - getLocalizedName(headerName, localizationMap) - ); -} - -function findAndChangeTargetData( - worksheet: any, - mappingData: any, - headers: any, - localizationMap: any -) { - logger.info( - `Received for Target mapping, enitity count : ${ - Object.keys(mappingData)?.length - }` - ); - - if (headers == null || headers.length == 0) { - throwError("Error", 500, "Mapping not found in MDMS for Campaign"); - } - logger.info( - `Received for Target mapping, headers count : ${ - headers?.length - }` - ); - logger.debug( - `headers: ${getFormattedStringForDebug(headers)}` - ); - let headersInSheet = worksheet.getRow(1).values; - const mappedData: any = {}; - // Iterate through rows in Sheet1 (starting from row 2 to skip the header) - worksheet.eachRow((row: any, rowIndex: number) => { - if (rowIndex === 1) return; // Skip the header row - const column1Value = row.getCell( - getHeaderIndex( - headersInSheet, - config?.boundary?.boundaryCode, - localizationMap - ) - ).value; // Get the value from column 1 - logger.debug( - `column1Value: ${getFormattedStringForDebug(column1Value)}` - ); - if (mappingData?.[column1Value] && headers != null && headers.length > 0) { - // Update columns 5 and 6 if column 1 value matches - headers.forEach((header: any) => { - header.from.forEach((fromValue: any) => { - row.getCell( - getHeaderIndex(headersInSheet, header?.to, localizationMap) - ).value = - mappingData?.[column1Value]?.additionalDetails?.[ - fromValue - ]; - logger.debug( - `headers to: ${getFormattedStringForDebug(getLocalizedName(header?.to, localizationMap))}` - ); - }); - }) - mappedData[column1Value] = rowIndex; - } else { - logger.info(`not doing anything if taregt cel not found`); - // Default values for other rows - // row.getCell(6).value = ""; - // row.getCell(7).value = "Inactive"; - } - }); - logger.info( - `Updated the boundary & active/inactive status information in Target received from the microplan` - ); - logger.info( - `mapping completed for Target enitity count : ${ - Object.keys(mappedData)?.length - }` - ); - logger.info( - `mapping not found for Target entity count : ${ - Object.keys(mappingData)?.length - Object.keys(mappedData)?.length - }` - ); - return worksheet; -} - -const getBoundariesFromCampaign = (CampaignDetails: any = {}) => { - logger.info("fetching all boundaries in that CampaignDetails"); - const boundaries = CampaignDetails?.boundaries?.map((obj: any) => obj?.code); - logger.debug( - `boundaries in that CampaignDetails are :${getFormattedStringForDebug( - boundaries - )}` - ); - return boundaries; -}; - -export const fetchUserData = async (request: any, localizationMap: any) => { - const { tenantId, planConfigurationId, campaignId } = - request.body.MicroplanDetails; - logger.info( - `doing the user data fetch for planConfigurationId: ${planConfigurationId} and campaignId: ${campaignId} ` - ); - const userRoleMapping = await fetchUserRoleMappingFromMDMS(tenantId); - logger.info(`got the user mapping from the plan api`); - const hierarchySchemaDataForConsole = await searchMDMS( - ["console"], - "HCM-ADMIN-CONSOLE.HierarchySchema", - request.body.RequestInfo - ); - const planResponse = await searchPlan( - planConfigurationId, - tenantId, - getBoundariesFromCampaign(request.body.CampaignDetails)?.length - ); - const boundariesOfCampaign = await getBoundaryInformation( - request.body.CampaignDetails, - request.body.CampaignDetails?.hierarchyType, - tenantId - ); - const filteredBoundariesAtWhichUserGetsCreated = - getFilteredBoundariesAtWhichUserGetsCreated( - boundariesOfCampaign, - hierarchySchemaDataForConsole?.mdms - ); - logger.debug( - `boundariesOfCampaign : ${getFormattedStringForDebug(boundariesOfCampaign)}` - ); - - const filteredBoundaryCodeMapWithChildrens = - enrichBoundariesWithTheSelectedChildrens( - boundariesOfCampaign, - filteredBoundariesAtWhichUserGetsCreated - ); - logger.debug( - `filteredBoundaryCodeMapWithChildrens : ${getFormattedStringForDebug( - filteredBoundaryCodeMapWithChildrens - )}` - ); - - const boundaryWithRoleMap = getUserRoleMapWithBoundaryCode( - planResponse, - userRoleMapping - ); - logger.debug( - `created userBoundaryMap :${getFormattedStringForDebug( - boundaryWithRoleMap - )}` - ); - - const consolidatedUserRolesPerBoundary = consolidateUserRoles( - boundaryWithRoleMap, - filteredBoundaryCodeMapWithChildrens - ); - - logger.debug( - `created final consolidatedUserRolesPerBoundary :${getFormattedStringForDebug( - consolidatedUserRolesPerBoundary - )}` - ); - const generatedUserTemplateFileStoreId = await getTheGeneratedResource( - campaignId, - tenantId, - "userWithBoundary", - request.body.CampaignDetails?.hierarchyType - ); - logger.debug( - `downloadresponse userWithBoundary ${getFormattedStringForDebug( - generatedUserTemplateFileStoreId - )}` - ); - const fileUrl = await fetchFileFromFilestore( - generatedUserTemplateFileStoreId, - tenantId - ); - logger.debug( - `downloadresponse userWithBoundary ${getFormattedStringForDebug(fileUrl)}` - ); - - const workbook = await getExcelWorkbookFromFileURL( - fileUrl, - getLocalizedName(config?.user.userTab, localizationMap) - ); - logger.info(`workbook created for user`); - - const updatedWorksheet = await findAndChangeUserData( - workbook.getWorksheet( - getLocalizedName(config?.user.userTab, localizationMap) - ), - consolidatedUserRolesPerBoundary - ); - logger.info( - `workbook updated for user with the data received from microplan` - ); - const responseData = - updatedWorksheet && (await createAndUploadFile(workbook, request)); - logger.info("user File updated successfully:" + JSON.stringify(responseData)); - if (responseData?.[0]?.fileStoreId) { - logger.info( - "user File updated successfully:" + - JSON.stringify( - responseData?.[0]?.fileStoreId + " for campaignid : " + campaignId - ) - ); - } else { - throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); - } - - await updateCampaignDetailsAfterSearch( - request, - { - fileStoreId: responseData?.[0]?.fileStoreId, - id: "not-validated", - }, - "user" - ); - - logger.info( - `updated the resources of user for campaignid : ${campaignId} and planid: ${planConfigurationId} ` - ); -}; - -export async function updateCampaignDetailsAfterSearch( - request: any, - resourceObject: any, - type: string -) { - const { tenantId, campaignId } = request.body.MicroplanDetails; - const campaignDetails = { - tenantId: tenantId, - ids: [campaignId], - }; - const searchedCampaignResponse = await searchProjectTypeCampaignService( - campaignDetails - ); - const searchedCamapignObject = - searchedCampaignResponse?.CampaignDetails?.[0] || null; - if (searchedCamapignObject != null) { - const newRequestBody = { - RequestInfo: request.body.RequestInfo, // Retain the original RequestInfo - CampaignDetails: searchedCamapignObject, // campaigndetails from search response - }; - const req: any = replicateRequest(request, newRequestBody); - // Validate input structure - if (resourceObject) { - let resourceFound = false; // Flag to track if resource is updated - - // Loop through resources to update or append as needed - searchedCamapignObject?.resources?.forEach((resource: any) => { - if (resource.type === type) { - resource.filestoreId = resourceObject?.fileStoreId; - resource.resourceId = resourceObject?.id; - logger.info( - `Updated resource of type ${type} with filestoreId: ${resourceObject.filestoreId}` - ); - resourceFound = true; - } - }); - - // If no resource of the given type was found, append a new one - if (!resourceFound) { - searchedCamapignObject?.resources.push({ - type: type, - filename: `filled-${type}-data-from-microplan.xlsx`, // Dynamically naming based on type - filestoreId: resourceObject?.fileStoreId, - resourceId: resourceObject?.id, - }); - logger.info(`Appended new resource of type ${type}`); - } - req.body.CampaignDetails = searchedCamapignObject; - } else { - console.error( - "Invalid structure in CampaignDetails or fileDetails. Ensure both are non-empty arrays." - ); - } - - // Call external service after updating the campaign details - await updateProjectTypeCampaignService(req); - } else { - throwError( - "CAMPAIGN", - 500, - "CAMPAIGN_SEARCH_ERROR", - "Error in Campaign Search" - ); - } -} - -export async function validateSheet( - request: any, - tenantId: any, - type: any, - fileStoreId: any, - campaignId: any, - hierarchyType: any -) { - let dataCreateBody = { - ResourceDetails: { - tenantId: tenantId, - type: type, - fileStoreId: fileStoreId, - action: "validate", - campaignId: campaignId, - hierarchyType: hierarchyType, - additionalDetails: {}, - }, - }; - - // Now merging defaultRequestInfo *with* dataCreateBody, so both are preserved - const newRequest: any = { - body: { ...request.body, ...dataCreateBody }, // Spread both objects to keep both their properties - }; - - try { - const resourceDetails:any = await createAndPollForCompletion(newRequest); - logger.info(`validation results :: ${resourceDetails?.[0]?.id} & status: ${resourceDetails?.[0]?.status}`) - logger.debug(`Final result:, ${getFormattedStringForDebug(resourceDetails)}`); - return resourceDetails; - } catch (error) { - logger.error( - `Error during resource creation and polling:for type ${type}`, - error - ); - logger.info(`setting resource event it fails for ${type}`); - return [{ ...dataCreateBody?.ResourceDetails, id: "not-validated" }]; - } -} -// sample oundary -//{code: "MICROPLAN_MO", name: "MICROPLAN_MO", parent:"", type: "COUNTRY", isRoot: true, includeAllChildren: false} -const getFilteredBoundariesAtWhichUserGetsCreated = ( - boundaries = [], - hierarchySchemaDataForConsole: any[] -) => { - // setting default value in case data is not present - let consolidateUserAtForConsole = "LOCALITY"; - if (hierarchySchemaDataForConsole?.length > 0) { - consolidateUserAtForConsole = - hierarchySchemaDataForConsole[0]?.data?.consolidateUsersAt; - logger.info( - "Taking value " + - consolidateUserAtForConsole + - " for user at console as it is present in mdms data" - ); - } else { - logger.info( - "Taking default value " + - consolidateUserAtForConsole + - " for user at console as it is not present in mdms data" - ); - } - //add config at which level grouping will happen. hardcoded to loclaity - const filteredBoundariesAtWhichUserGetsCreated = boundaries?.filter( - (boundary: any) => boundary?.type == consolidateUserAtForConsole - ); - logger.info( - `filteredBoundariesAtWhichUserGetsCreated count is ${filteredBoundariesAtWhichUserGetsCreated?.length}` - ); - logger.debug( - `filteredBoundariesAtWhichUserGetsCreated are ${getFormattedStringForDebug( - filteredBoundariesAtWhichUserGetsCreated - )}` - ); - return filteredBoundariesAtWhichUserGetsCreated; -}; - -const getBoundaryInformation = async ( - CampaignDetails: any, - boundaryHierarchy: string, - tenantId: string -) => { - const boundaries = CampaignDetails?.boundaries; - if (boundaries?.some((boundary: any) => boundary?.includeAllChildren)) { - const boundaryResponse = await searchBoundaryRelationshipData( - tenantId, - boundaryHierarchy, - true - ); - logger.info("got the boundary hierarchy response"); - if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { - logger.info("got the boundary hierarchy response"); - } - - return boundaries; - } -}; - -const enrichBoundariesWithTheSelectedChildrens = ( - allSelectedBoundaries = [], - filteredBoundaries = [] -) => { - const enrichedMap: any = {}; - filteredBoundaries?.map((boundary: any) => { - enrichedMap[boundary?.code] = allSelectedBoundaries?.filter( - (bound: any) => bound.parent == boundary?.code - ); - }); - return enrichedMap; -}; -export async function fetchUserRoleMappingFromMDMS(tenantId: any) { - const MdmsCriteria: MDMSModels.MDMSv1RequestCriteria = { - MdmsCriteria: { - tenantId: tenantId, - moduleDetails: [ - { - moduleName: "HCM-ADMIN-CONSOLE", - masterDetails: [ - { - name: "microplanIntegration", - }, - ], - }, - ], - }, - }; - const data = await searchMDMSDataViaV1Api(MdmsCriteria); - const result: Record = {}; - - if ( - data?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.microplanIntegration && - Array.isArray(data.MdmsRes["HCM-ADMIN-CONSOLE"].microplanIntegration) - ) { - const integrations = - data.MdmsRes["HCM-ADMIN-CONSOLE"].microplanIntegration; - - integrations.forEach((integration: any) => { - const type = integration.type; - - if (!result[type]) { - result[type] = []; - } - - integration.mappings.forEach((mapping: any) => { - result[type].push({ - to: mapping.to, - from: mapping.from, - filter: mapping.filter, - }); - }); - }); - } - - return result; -} diff --git a/health-services/project-factory/src/server/utils/microplanUtils.ts b/health-services/project-factory/src/server/utils/microplanUtils.ts deleted file mode 100644 index a188e01d9d3..00000000000 --- a/health-services/project-factory/src/server/utils/microplanUtils.ts +++ /dev/null @@ -1,493 +0,0 @@ -import { resourceDataStatuses } from "../config/constants"; -import { v4 as uuidv4 } from 'uuid'; -import config from "./../config"; -import { throwError } from "./genericUtils"; -import { httpRequest } from "./request"; -import { callMdmsData, getSheetData } from "./../api/genericApis"; -import { checkIfSourceIsMicroplan, getLocalizedName } from "./campaignUtils"; -import createAndSearch from "../config/createAndSearch"; -import { produceModifiedMessages } from "../kafka/Producer"; -import { searchMDMSDataViaV2Api } from "../api/coreApis"; -import { getCampaignSearchResponse } from "../api/campaignApis"; - - -export const filterData = (data: any) => { - return data.filter((item: any) => { - // Create a shallow copy of the object without `#status#` and `#errorDetails#` - const { '#status#': status, '#errorDetails#': errorDetails, ...rest } = item; - - // Check if only `!row#number!` remains after removing status and errorDetails - const remainingKeys = Object.keys(rest).filter(key => key !== '!row#number!'); - - // Include the item if any other properties exist besides `!row#number!` - return remainingKeys.length > 0; - }); -}; - - - - - -export async function getUserDataFromMicroplanSheet(request: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { - const fileResponse = await httpRequest(`${config.host.filestore}${config.paths.filestore}/url`, {}, { tenantId, fileStoreIds: fileStoreId }, "get"); - if (!fileResponse?.fileStoreIds?.[0]?.url) { - throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); - } - const rolesForMicroplanWithCode = await getRolesForMicroplan(tenantId, localizationMap, true); - const rolesCodeMapping = rolesForMicroplanWithCode.reduce((acc: any, role: any) => { - acc[role.role] = role.code; - return acc; - }, {}); - const userMapping: any = {}; - for (const sheetName of Object.keys(rolesCodeMapping)) { - const dataOfSheet = filterData(await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, sheetName, true, undefined, localizationMap)); - for (const user of dataOfSheet) { - user.role = rolesCodeMapping?.[sheetName]; - user["!sheet#name!"] = sheetName; - const emailKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_EMAIL_MICROPLAN", localizationMap) - user[emailKey] = user[emailKey]?.text || user[emailKey]; - const phoneNumberKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER_MICROPLAN", localizationMap) - if (!userMapping[user[phoneNumberKey]]) { - userMapping[user[phoneNumberKey]] = [user] - } - else { - userMapping[user[phoneNumberKey]].push(user) - } - } - } - const allUserData = getAllUserData(request, userMapping, localizationMap); - return allUserData; -} - -export function getAllUserData(request: any, userMapping: any, localizationMap: any) { - const emailKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_EMAIL_MICROPLAN", localizationMap); - const nameKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_NAME_MICROPLAN", localizationMap); - validateInConsistency(request, userMapping, emailKey, nameKey); - validateNationalDuplicacy(request, userMapping, localizationMap); - const dataToCreate: any = []; - for (const phoneNumber of Object.keys(userMapping)) { - const roles = userMapping[phoneNumber].map((user: any) => user.role).join(','); - const email = userMapping[phoneNumber]?.[0]?.[emailKey] || null; - const name = userMapping[phoneNumber]?.[0]?.[nameKey]; - const rowNumbers = userMapping[phoneNumber].map((user: any) => user["!row#number!"]); - const sheetNames = userMapping[phoneNumber].map((user: any) => user["!sheet#name!"]); - const tenantId = request?.body?.ResourceDetails?.tenantId; - const rowXSheet = rowNumbers.map((row: any, index: number) => ({ - row: row, - sheetName: sheetNames[index] - })); - dataToCreate.push({ ["!row#number!"]: rowXSheet, tenantId: tenantId, employeeType: "TEMPORARY", user: { emailId: email, name: name, mobileNumber: phoneNumber, roles: roles } }); - } - request.body.dataToCreate = dataToCreate; - return convertDataSheetWise(userMapping); -} - -function validateInConsistency(request: any, userMapping: any, emailKey: any, nameKey: any) { - const overallInconsistencies: string[] = []; // Collect all inconsistencies here - - enrichInconsistencies(overallInconsistencies, userMapping, nameKey, emailKey); - if (overallInconsistencies.length > 0) { - request.body.ResourceDetails.status = resourceDataStatuses.invalid - } - - request.body.sheetErrorDetails = Array.isArray(request.body.sheetErrorDetails) ? [...request.body.sheetErrorDetails, ...overallInconsistencies] : overallInconsistencies; -} - -function validateNationalDuplicacy(request: any, userMapping: any, localizationMap: any) { - const duplicates: any[] = []; - - for (const phoneNumber in userMapping) { - const roleMap: any = {}; - const users = userMapping[phoneNumber]; - - for (const user of users) { - const userRole = user?.role; - if (userRole?.startsWith("ROOT_")) { - // Trim the role - const trimmedRole = userRole.replace("ROOT_", ""); - - // Check for duplicates in the roleMap - if (roleMap[trimmedRole] && roleMap[trimmedRole]["!sheet#name!"] != user["!sheet#name!"]) { - const errorMessage: any = `An user with ${getLocalizedName(trimmedRole, localizationMap)} role can’t be assigned to ${getLocalizedName(userRole, localizationMap)} role`; - duplicates.push({ rowNumber: user["!row#number!"], sheetName: user["!sheet#name!"], status: "INVALID", errorDetails: errorMessage }); - } else { - roleMap[trimmedRole] = user; - } - } - else { - const trimmedRole = userRole; - const errorMessage: any = `An user with ${getLocalizedName("ROOT_" + trimmedRole, localizationMap)} role can’t be assigned to ${getLocalizedName(userRole, localizationMap)} role`; - if (roleMap[trimmedRole] && roleMap[trimmedRole]["!sheet#name!"] != user["!sheet#name!"]) { - duplicates.push({ rowNumber: user["!row#number!"], sheetName: user["!sheet#name!"], status: "INVALID", errorDetails: errorMessage }); - } else { - roleMap[trimmedRole] = user; - } - } - } - } - if (duplicates.length > 0) { - request.body.ResourceDetails.status = resourceDataStatuses.invalid - } - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...duplicates] : duplicates; -} - -function convertDataSheetWise(userMapping: any) { - const sheetMapping: any = {} - for (const phoneNumber in userMapping) { - const users = userMapping[phoneNumber]; - for (const user of users) { - const sheetName = user["!sheet#name!"]; - if (!sheetMapping[sheetName]) { - sheetMapping[sheetName] = []; - } - sheetMapping[sheetName].push(user); - } - } - return sheetMapping; -} - -function getInconsistencyErrorMessage(phoneNumber: any, userRecords: any) { - // Create the error message mentioning all the records for this phone number - const errors: any = [] - const errorMessage = `User details for the same contact number don't match. Please check the user's name or email ID`; - for (const record of userRecords) { - errors.push({ rowNumber: record.row, sheetName: record.sheet, status: "INVALID", errorDetails: errorMessage }); - } - - return errors -} - -function enrichInconsistencies(overallInconsistencies: any, userMapping: any, nameKey: string, emailKey: string) { - for (const phoneNumber in userMapping) { - if (phoneNumber && phoneNumber != 'undefined') { - const users = userMapping[phoneNumber]; - const userRecords: any[] = []; - - // Collect all user data for this phone number - for (const user of users) { - userRecords.push({ - row: user["!row#number!"], - sheet: user["!sheet#name!"], - name: user[nameKey], - email: user[emailKey] - }); - } - - const errorMessage = getInconsistencyErrorMessage(phoneNumber, userRecords); - - // Check for any inconsistencies by comparing all records with each other - const firstRecord = userRecords[0]; // Take the first record as baseline - const inconsistentRecords = userRecords.filter(record => - record.name !== firstRecord.name || record.email !== firstRecord.email - ); - if (inconsistentRecords.length > 0) { - overallInconsistencies.push(...errorMessage); // Collect all inconsistencies - } - } - } -} - -function lockTillStatus(workbook: any) { - workbook.worksheets.forEach((sheet: any) => { - const statusCell = findStatusColumn(sheet); // Find the status column - - if (!statusCell) { - // Lock the entire sheet if no "#status#" found - sheet.protect('passwordhere', { - selectLockedCells: true, - selectUnlockedCells: false - }); - } else { - // Lock the entire sheet but allow selecting unlocked cells - sheet.protect('passwordhere', { - selectLockedCells: true, - selectUnlockedCells: true // Allow selecting unlocked cells - }); - - // Lock the first row - sheet.getRow(1).eachCell({ includeEmpty: true }, (cell: any) => { - cell.protection = { locked: true }; - }); - - // Lock every column starting from the "#status#" column - const statusColIndex = statusCell.col; - for (let col = statusColIndex; col <= sheet.columnCount; col++) { - sheet.getColumn(col).eachCell({ includeEmpty: true }, (cell: any) => { - cell.protection = { locked: true }; - }); - } - - // Unlock the rest of the sheet (if needed) - sheet.eachRow((row: any, rowIndex: any) => { - if (rowIndex > 1) { // Skip first row - row.eachCell({ includeEmpty: true }, (cell: any) => { - if (cell.col < statusColIndex) { // Unlock cells before the status column - cell.protection = { locked: false }; - } - }); - } - }); - } - }); -} - -export function lockWithConfig(sheet: any) { - for (let row = 1; row <= Number.parseInt(config.values.unfrozeTillRow); row++) { - for (let col = 1; col <= Number.parseInt(config.values.unfrozeTillColumn); col++) { - const cell = sheet.getCell(row, col); - if (!cell.value && cell.value !== 0) { - cell.protection = { locked: false }; - } - } - } - sheet.protect('passwordhere', { selectLockedCells: true, selectUnlockedCells: true }); -} - -function lockAll(workbook: any) { - workbook.worksheets.forEach((sheet: any) => { - lockWithConfig(sheet); - }) -} - - -export function lockSheet(request: any, workbook: any) { - if (request?.body?.ResourceDetails?.type == 'create') { - lockAll(workbook); - } - else { - lockTillStatus(workbook); - } -} - -// Helper function to find the column containing "#status#" -function findStatusColumn(sheet: any) { - let statusCell: any = null; - - // Loop through each row - sheet.eachRow((row: any, rowIndex: any): any => { - // Loop through each cell in the row - row.eachCell((cell: any, colIndex: any) => { - // If "#status#" is found, capture the row and column - if (cell.value === "#status#") { - statusCell = { row: rowIndex, col: colIndex }; - } - }); - - // If the status cell is found, stop further iteration - if (statusCell) { - return false; // This will only break the row loop, not the function - } - }); - - // Return the found statusCell, or null if not found - return statusCell; -} - -export function changeCreateDataForMicroplan(request: any, element: any, rowData: any, localizationMap?: any) { - const type = request?.body?.ResourceDetails?.type; - const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; - if (type == 'facility') { - const projectType = request?.body?.projectTypeCode; - const facilityCapacityColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN_${projectType}`, localizationMap); - if (rowData[facilityCapacityColumn] >= 0) { - element.storageCapacity = rowData[facilityCapacityColumn] - } - if (activeColumnName && rowData[activeColumnName] == "Active") { - if (Array(request?.body?.facilityDataForMicroplan) && request?.body?.facilityDataForMicroplan?.length > 0) { - request.body.facilityDataForMicroplan.push({ ...rowData, facilityDetails: element }) - } - else { - request.body.facilityDataForMicroplan = [{ ...rowData, facilityDetails: element }] - } - } - } -} - -export function updateFacilityDetailsForMicroplan(request: any, createdData: any) { - const facilityDataForMicroplan = request?.body?.facilityDataForMicroplan; - if (Array.isArray(facilityDataForMicroplan) && facilityDataForMicroplan.length > 0) { - for (const element of facilityDataForMicroplan) { - const rowNumber = element['!row#number!']; - const createdDataWithMatchingRowNumber = createdData.find((data: any) => data['!row#number!'] == rowNumber) || null; - if (createdDataWithMatchingRowNumber) { - element.facilityDetails.id = createdDataWithMatchingRowNumber.id - } - } - } -} - - -export async function createPlanFacilityForMicroplan(request: any, localizationMap?: any) { - if (request?.body?.ResourceDetails?.type == 'facility' && request?.body?.ResourceDetails?.additionalDetails?.source == 'microplan') { - const allFacilityDatas = request?.body?.facilityDataForMicroplan; - const planConfigurationId = request?.body?.ResourceDetails?.additionalDetails?.microplanId; - request.body.MicroplanDetails = { - tenantId: request?.body?.ResourceDetails?.tenantId, - planConfigurationId: planConfigurationId - } - const planConfigSearchResponse = await planConfigSearch(request); - const planConfigurationName = planConfigSearchResponse?.PlanConfiguration?.[0]?.name; - for (const element of allFacilityDatas) { - const produceObject: any = getPlanFacilityObject(request, element, planConfigurationName, planConfigurationId, localizationMap); - await produceModifiedMessages(produceObject, config?.kafka?.KAFKA_SAVE_PLAN_FACILITY_TOPIC); - } - } -} - -function getPlanFacilityObject(request: any, element: any, planConfigurationName: any, planConfigurationId: any, localizationMap?: any) { - const residingBoundariesColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN`, localizationMap); - const singularResidingBoundary = element?.[residingBoundariesColumn] - ? element[residingBoundariesColumn].split(",")[0] - : null; - const facilityStatus = element?.facilityDetails?.isPermanent ? "Permanent" : "Temporary"; - const facilityType = element?.facilityDetails?.usage; - const hierarchyType = request?.body?.ResourceDetails?.hierarchyType; - const currTime = new Date().getTime(); - const planFacilityProduceObject: any = { - PlanFacility: { - id: uuidv4(), - tenantId: element?.facilityDetails?.tenantId, - planConfigurationId: planConfigurationId, - facilityId: element?.facilityDetails?.id, - residingBoundary: singularResidingBoundary, - facilityName: element?.facilityDetails?.name, - serviceBoundaries: null, - planConfigurationName: planConfigurationName, - additionalDetails: { - capacity: element?.facilityDetails?.storageCapacity, - facilityName: element?.facilityDetails?.name, - facilityType: facilityType, - facilityStatus: facilityStatus, - assignedVillages: [], - servingPopulation: 0, - hierarchyType: hierarchyType - }, - active: true, - auditDetails: { - createdBy: request?.body?.RequestInfo?.userInfo?.uuid, - lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, - createdTime: currTime, - lastModifiedTime: currTime - } - } - } - const fixedPostColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_FACILITY_FIXED_POST_MICROPLAN`, localizationMap); - if (element?.[fixedPostColumn]) { - planFacilityProduceObject.PlanFacility.additionalDetails.fixedPost = element?.[fixedPostColumn] - } - return planFacilityProduceObject; -} - - -export async function planFacilitySearch(request: any) { - const { tenantId, planConfigurationId } = request.body.MicroplanDetails; - const searchBody = { - RequestInfo: request.body.RequestInfo, - PlanFacilitySearchCriteria: { - tenantId: tenantId, - planConfigurationId: planConfigurationId - } - } - - const searchResponse = await httpRequest(config.host.planServiceHost + config.paths.planFacilitySearch, searchBody); - return searchResponse; -} - -export function planConfigSearch(request: any) { - const { tenantId, planConfigurationId } = request.body.MicroplanDetails; - const searchBody = { - RequestInfo: request.body.RequestInfo, - PlanConfigurationSearchCriteria: { - tenantId: tenantId, - id: planConfigurationId - } - } - - const searchResponse = httpRequest(config.host.planServiceHost + config.paths.planConfigSearch, searchBody); - return searchResponse; -} - -export function modifyBoundaryIfSourceMicroplan(boundaryData: any[], request: any) { - // Check if the request is for a source microplan and the type is 'facilityWithBoundary' - if (request?.body?.isSourceMicroplan && request?.query?.type == 'facilityWithBoundary') { - // Extract the boundary hierarchy from the request body - const hierarchy = request?.body?.hierarchyType?.boundaryHierarchy; - let villageIndex: any; - // Determine the `villageIndex` based on the hierarchy length if present - if (hierarchy) { - // Set `villageIndex` to the last element in the hierarchy (boundary hierarchy depth) - villageIndex = hierarchy?.length - 1; - } else { - // If no hierarchy is provided, calculate the `villageIndex` dynamically - let maxBoundaryDataLength = 0; - - // Iterate through `boundaryData` to find the maximum length of any boundary array - for (const boundary of boundaryData) { - if (boundary?.length > maxBoundaryDataLength) { - maxBoundaryDataLength = boundary?.length; - } - } - - // If boundary data has sufficient depth, set `villageIndex` to the second-to-last level - if (maxBoundaryDataLength >= 2) { - villageIndex = maxBoundaryDataLength - 2; - } - } - // Filter out boundaries that don't have the `villageIndex` - boundaryData = boundaryData.filter((boundary: any) => boundary?.[villageIndex]); - } - return boundaryData; -} - -export async function getRolesForMicroplan(tenantId: string, localizationMap: any, fetchWithRoleCodes: boolean = false) { - const MdmsCriteria: any = { - tenantId: tenantId, - schemaCode: "hcm-microplanning.rolesForMicroplan", - }; - const mdmsResponse: any = await searchMDMSDataViaV2Api(MdmsCriteria); - if (mdmsResponse?.mdms?.length > 0) { - if (fetchWithRoleCodes) { - // return array { role : "role", code : "roleCode" } - return mdmsResponse?.mdms?.filter((role: any) => role?.isActive) - ?.map((role: any) => ({ role: getLocalizedName(role?.data?.roleCode, localizationMap), code: role?.data?.roleCode })); - } - else { - return mdmsResponse?.mdms - ?.filter((role: any) => role?.isActive) // Filter roles with isActive true - ?.map((role: any) => getLocalizedName(role?.data?.roleCode, localizationMap)); // Map to extract the role - } - } - else { - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", `Some error occured during rolesForMicroplan mdms search.`); - return []; - } -} - -export async function isMicroplanRequest(request: any): Promise { - const campaignId = request?.query?.campaignId || request?.body?.ResourceDetails?.campaignId; - if (campaignId == "microplan") { - return true; - } - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - return checkIfSourceIsMicroplan(campaignObject); -} - -export async function getReadMeConfigForMicroplan(request: any) { - const mdmsResponse = await callMdmsData(request, "HCM-ADMIN-CONSOLE", "ReadMeConfig", request?.query?.tenantId); - if (mdmsResponse?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig) { - const readMeConfigsArray = mdmsResponse?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig - for (const readMeConfig of readMeConfigsArray) { - if (readMeConfig?.type == `${request?.query?.type}_MICROPLAN`) { - return readMeConfig - } - } - throwError("MDMS", 500, "INVALID_README_CONFIG", `Readme config for type ${request?.query?.type} not found.`); - return {} - } - else { - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", `Some error occured during readme config mdms search.`); - return {}; - } -} - diff --git a/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts b/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts deleted file mode 100644 index eeb6c2c8d9d..00000000000 --- a/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts +++ /dev/null @@ -1,768 +0,0 @@ -import { searchProjectTypeCampaignService } from "../service/campaignManageService"; -import { getLocalizedHeaders, replicateRequest, throwError } from "./genericUtils"; -import { httpRequest } from "./request"; -import config from "../config/index"; -import { getLocalizedName } from "./campaignUtils"; -import { logger } from "./logger"; -import { callGenerate } from "./generateUtils"; -// import { getCampaignSearchResponse } from "server/api/campaignApis"; -import { getExcelWorkbookFromFileURL } from "./excelUtils"; -import { createAndUploadFile, getSheetData, getTargetSheetData } from "../api/genericApis"; -import { searchDataService } from "../service/dataManageService"; -import { produceModifiedMessages } from "../kafka/Producer"; - -async function getParentCampaignObject(request: any, parentId: any) { - try { - // const searchBodyForParent = { - // RequestInfo: request.body.RequestInfo, - const CampaignDetails = { - tenantId: request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId || request?.body?.CampaignDetails?.tenantId, - ids: [parentId] - } - // }; - // const req: any = replicateRequest(request, searchBodyForParent); - const parentSearchResponse = await searchProjectTypeCampaignService(CampaignDetails); - return parentSearchResponse?.CampaignDetails?.[0]; - } catch (error) { - logger.error("Error fetching parent campaign object:", error); - throwError("CAMPAIGN", 400, "PARENT_CAMPAIGN_ERROR", "Parent Campaign fetching error "); - } -} - -function getCreatedResourceIds(resources: any, type: any) { - const processedType = type === 'boundary' - ? 'boundaryWithTarget' - : (type.includes('With') ? type.split('With')[0] : type); - return resources - .filter((item: any) => item.type === processedType) - .map((item: any) => item.createResourceId); -} - -function buildSearchCriteria(request: any, createdResourceId: any, type: any) { - const processedType = type === 'boundary' - ? 'boundaryWithTarget' - : (type === 'boundaryWithTarget' ? type : (type.includes('With') ? type.split('With')[0] : type)); - - const requestInfo = request?.body - ? request.body.RequestInfo - : { RequestInfo: request?.RequestInfo }; - return { - RequestInfo: requestInfo, - SearchCriteria: { - id: createdResourceId, - tenantId: request?.query?.tenantId || request?.CampaignDetails?.tenantId, - type: processedType - } - }; -} - -async function fetchFileUrls(request: any, processedFileStoreIdForUSerOrFacility: any) { - try { - const reqParamsForFetchingFile = { - tenantId: request?.query?.tenantId, - fileStoreIds: processedFileStoreIdForUSerOrFacility - }; - return await httpRequest( - `${config?.host?.filestore}${config?.paths?.filestorefetch}`, - request?.body, - reqParamsForFetchingFile, - "get" - ); - } catch (error) { - logger.error("Error fetching file URLs:", error); - throw error; - } -} - - - -function modifyProcessedSheetData(type: any, sheetData: any, schema: any, localizationMap?: any) { - if (!sheetData || sheetData.length === 0) return []; - - const originalHeaders = type === config?.facility?.facilityType ? [config?.facility?.facilityCodeColumn, ...schema?.columns] : schema?.columns; - - let localizedHeaders = getLocalizedHeaders(originalHeaders, localizationMap); - - // Map each object in sheetData to an array of values corresponding to the header order - let dataRows = sheetData.map((row: any) => { - return localizedHeaders.map((header: any) => row[header] || ''); - }); - - const updatedHeaders = localizedHeaders.map((header: any) => header === getLocalizedName(config?.boundary?.boundaryCodeMandatory, localizationMap) ? - getLocalizedName(config?.boundary?.boundaryCodeOld, localizationMap) : header) - - const updatedWithAdditionalHeaders = [...updatedHeaders, config?.boundary?.boundaryCodeMandatory] - localizedHeaders = getLocalizedHeaders(updatedWithAdditionalHeaders, localizationMap); - - dataRows = dataRows.map((row: any, index: number) => { - const boundaryCodeValue = sheetData[index][getLocalizedName(config?.boundary?.boundaryCodeMandatory, localizationMap)] || ''; - return [...row, boundaryCodeValue]; - }); - - // Combine headers and dataRows - const modifiedData = [localizedHeaders, ...dataRows]; - - return modifiedData; -} - -function freezeUnfreezeColumnsForProcessedFile(sheet: any, columnsToFreeze: number[], columnsToUnfreeze: number[]) { - // First, unfreeze specified columns - columnsToUnfreeze.forEach(colNumber => { - for (let row = 1; row <= sheet.rowCount; row++) { - const cell = sheet.getCell(row, colNumber); - cell.protection = { locked: false }; // Unfreeze the cell - } - }); - - // Then, freeze specified columns - columnsToFreeze.forEach(colNumber => { - for (let row = 1; row <= sheet.rowCount; row++) { - const cell = sheet.getCell(row, colNumber); - cell.protection = { locked: true }; // Freeze the cell - } - }); -} - - -function getColumnIndexByHeader(sheet: any, headerName: string): number { - // Get the first row (assumed to be the header row) - const firstRow = sheet.getRow(1); - - // Find the column index where the header matches the provided name - for (let col = 1; col <= firstRow.cellCount; col++) { - const cell = firstRow.getCell(col); - if (cell.value === headerName) { - return col; // Return the column index (1-based) - } - } - return 1; -} - -// function validateBoundaryCodes(activeRows: any, localizationMap?: any) { -// const updatedBoundaryCodeKey = getLocalizedName('HCM_ADMIN_CONSOLE_UPDATED_BOUNDARY_CODE', localizationMap); -// const updatedBoundaryCodeValue = activeRows[updatedBoundaryCodeKey]; -// const boundaryCodeMandatoryKey = getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", localizationMap); -// const boundaryCodeMandatoryValue = activeRows[boundaryCodeMandatoryKey]; -// if (!updatedBoundaryCodeValue && !boundaryCodeMandatoryValue) { -// const errorDetails = { -// errors: [ -// { -// instancePath: '', -// schemaPath: '#/required', -// keyword: 'required', -// params: { -// missingProperty: `${updatedBoundaryCodeKey} and ${boundaryCodeMandatoryKey} both` -// }, -// message: `must have required properties ${`${updatedBoundaryCodeKey}, ${boundaryCodeMandatoryKey}`}` -// } -// ] -// }; - -// throw new Error(JSON.stringify(errorDetails)); -// } -// } - -async function checkAndGiveIfParentCampaignAvailable(request: any, campaignObject: any) { - if (campaignObject?.parentId) { - logger.info("enriching the parent campaign details for update flow"); - const parentCampaignObject = await getParentCampaignObject(request, campaignObject.parentId); - - if (parentCampaignObject?.status === "created" && !parentCampaignObject.isActive) { - request.body.parentCampaignObject = parentCampaignObject; - } - } -} - -function hideColumnsOfProcessedFile(sheet: any, columnsToHide: any[]) { - columnsToHide.forEach((column) => { - if (column > 0) { - sheet.getColumn(column).hidden = true; - } - }); -} - -function unhideColumnsOfProcessedFile(sheet: any, columnsToUnide: any) { - columnsToUnide.forEach((column: any) => { - if (column) { - sheet.getColumn(column).hidden = false; - } - }); -} - -function modifyNewSheetData(processedDistrictSheetData: any, newSheetData: any, headers: any, oldTargetColumnsToHide: any[], localizationMap?: any) { - let modifiedData = []; - const localizedHeaders = getLocalizedHeaders(headers, localizationMap); - if (processedDistrictSheetData && processedDistrictSheetData.length > 0) { - const dataRows = processedDistrictSheetData.map((row: any) => { - return localizedHeaders.map((header: any) => row[header] || ''); - }); - modifiedData = [localizedHeaders, ...dataRows]; - } else { - // If processedDistrictSheetData is not present, work only with newSheetData - modifiedData = [newSheetData]; - } - - const newData = updateTargetValues(modifiedData, newSheetData, localizedHeaders, oldTargetColumnsToHide, localizationMap); - return newData; -} - - -function updateTargetValues(originalData: any, newData: any, localizedHeaders: any, oldTargetColumnsToHide: any[], localizationMap?: any) { - - const boundaryCodeIndex = localizedHeaders.indexOf(getLocalizedName(config?.boundary?.boundaryCode, localizationMap)); - - // Update newData with matching values from originalData - newData = newData.map((newRow: any) => { - const matchingRow = originalData.find((originalRow: any) => - originalRow.slice(0, boundaryCodeIndex + 1).every((val: any, index: any) => val === newRow[index]) - ); - - return newRow.map((value: any, index: any) => - index > boundaryCodeIndex && matchingRow && value === '' - ? matchingRow[index] - : value - ); - }); - newData = newData.map((newRow: any, rowIndex: number) => { - const updatedValues: any[] = []; - for (let i = boundaryCodeIndex + 1; i < localizedHeaders.length; i++) { - updatedValues.push(newRow[i]); // Store original value - if (rowIndex === 0) { // Only modify the first row - const modifiedValue = `${newRow[i]}(OLD)`; // Create modified value with (OLD) suffix - newRow[i] = modifiedValue; // Update newRow[i] with the modified value - oldTargetColumnsToHide.push(modifiedValue); // Push the modified value - } - } - // Concatenate original values at the end of every row - return [...newRow, ...updatedValues]; - }); - return newData; -} - -function validateBoundariesIfParentPresent(request: any) { - const { parentCampaign, CampaignDetails } = request?.body || {}; - - if (parentCampaign) { - const errors: string[] = []; - const newBoundaries: any[] = []; - const parentCampaignBoundaryCodes = parentCampaign.boundaries.map((boundary: any) => boundary.code); - - CampaignDetails?.boundaries?.forEach((boundary: any) => { - if (parentCampaignBoundaryCodes.includes(boundary.code)) { - errors.push(boundary.code); - } else { - if (!boundary?.isRoot) { - newBoundaries.push(boundary); - } else { - throwError( - "COMMON", - 400, - "VALIDATION_ERROR", - `Boundary with code ${boundary.code} cannot be added as it is marked as root. Root boundary should come from the parent campaign.` - ); - } - } - }); - - if (errors.length > 0) { - throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Codes found already in Parent Campaign: ${errors.join(', ')}`); - } - request.body.boundariesCombined = [...parentCampaign.boundaries, ...newBoundaries]; - } - else { - request.body.boundariesCombined = request?.body?.CampaignDetails?.boundaries - } -} - - -async function callGenerateWhenChildCampaigngetsCreated(request: any) { - try { - const newRequestBody = { - RequestInfo: request?.body?.RequestInfo, - Filters: { - boundaries: request?.body?.boundariesCombined - } - }; - - const { query } = request; - const params = { - tenantId: request?.body?.CampaignDetails?.tenantId, - forceUpdate: 'true', - hierarchyType: request?.body?.CampaignDetails?.hierarchyType, - campaignId: request?.body?.CampaignDetails?.id - }; - - const newParamsBoundary = { ...query, ...params, type: "boundary" }; - const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); - await callGenerate(newRequestBoundary, "boundary"); - - const newParamsFacilityWithBoundary = { ...query, ...params, type: "facilityWithBoundary" }; - const newRequestFacilityWithBoundary = replicateRequest(request, newRequestBody, newParamsFacilityWithBoundary); - await callGenerate(newRequestFacilityWithBoundary, "facilityWithBoundary"); - - const newParamsUserWithBoundary = { ...query, ...params, type: "userWithBoundary" }; - const newRequestUserWithBoundary = replicateRequest(request, newRequestBody, newParamsUserWithBoundary); - await callGenerate(newRequestUserWithBoundary, "userWithBoundary"); - } - catch (error: any) { - logger.error(error); - throwError("COMMON", 400, "GENERATE_ERROR", `Error while generating user/facility/boundary: ${error.message}`); - } -} - - -function getBoundariesArray(parentCampaignBoundaries: any, campaignBoundaries: any) { - // Ensure both inputs are arrays or default to empty arrays - const validParentBoundaries = Array.isArray(parentCampaignBoundaries) ? parentCampaignBoundaries : []; - const validCampaignBoundaries = Array.isArray(campaignBoundaries) ? campaignBoundaries : []; - - return [...validParentBoundaries, ...validCampaignBoundaries]; -} - -async function getBoundariesFromCampaignSearchResponse(request: any, campaignDetails: any) { - let parentCampaignBoundaries: any[] = []; - if (campaignDetails?.parentId) { - const parentCampaignObject = await getParentCampaignObject(request, campaignDetails?.parentId); - parentCampaignBoundaries = parentCampaignObject?.boundaries; - } - return getBoundariesArray(parentCampaignBoundaries, campaignDetails?.boundaries) -} - -async function fetchProjectsWithProjectId(request: any, projectId: any, tenantId: any) { - const projectSearchBody = { - RequestInfo: request?.body?.RequestInfo || request?.RequestInfo, - Projects: [ - { - id: projectId, - tenantId: tenantId - } - ] - } - const projectSearchParams = { - tenantId: tenantId, - offset: 0, - limit: 1, - includeDescendants: true - } - logger.info("Project search params " + JSON.stringify(projectSearchParams)) - const projectSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectSearch, projectSearchBody, projectSearchParams); - if (projectSearchResponse?.Project && Array.isArray(projectSearchResponse?.Project) && projectSearchResponse?.Project?.length > 0) { - return projectSearchResponse; - } - else { - throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR") - return [] - } -} - - -async function fetchProjectsWithBoundaryCodeAndReferenceId(boundaryCode: any, tenantId: any, referenceId: any, RequestInfo?: any) { - try { - const projectSearchBody = { - RequestInfo: RequestInfo, - Projects: [ - { - address: { - boundary: boundaryCode, - }, - tenantId: tenantId, - referenceID: referenceId - } - ] - } - const projectSearchParams = { - tenantId: tenantId, - offset: 0, - limit: 1 - } - logger.info("Project search params " + JSON.stringify(projectSearchParams)) - const projectSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectSearch, projectSearchBody, projectSearchParams); - if (projectSearchResponse?.Project && Array.isArray(projectSearchResponse?.Project) && projectSearchResponse?.Project?.length > 0) { - return projectSearchResponse; - } - else { - return null; - } - } catch (error: any) { - throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR") - } -} - -function getBoundaryProjectMappingFromParentCampaign(request: any, project: any) { - - const boundarySet = new Set(); - - // Initialize result array with the project itself (id and boundary) - const result = [ - { - id: project.id, - boundary: project.address.boundary - }, - ...project.descendants.map((descendant: any) => ({ - id: descendant.id, - boundary: descendant.address.boundary - })) - ]; - - // Iterate over the result array to find matching boundaries and populate projectId - result.forEach((entry: any) => { - const boundary = entry.boundary; - boundarySet.add(boundary); - // Initialize the boundaryProjectMapping for this boundary if not present - if (!request?.body?.boundaryProjectMapping?.[boundary]) { - request.body.boundaryProjectMapping[boundary] = { parent: null, projectId: null }; - } - // Update the projectId in the request's boundaryProjectMapping - request.body.boundaryProjectMapping[boundary].projectId = entry.id; - }); - - return boundarySet; -} - - -async function fetchProjectFacilityWithProjectId(request: any, projectId: any, facilityId: any) { - try { - const { tenantId } = request?.body?.parentCampaign || request?.parentCampaign; - const projectSearchBody = { - RequestInfo: request?.body?.RequestInfo || request?.RequestInfo, - ProjectFacility: { - projectId: [ - projectId - ], - facilityId: [ - facilityId - ] - } - } - const projectSearchParams = { - tenantId: tenantId, - offset: 0, - limit: 1 - } - logger.info("Project search params " + JSON.stringify(projectSearchParams)) - const projectFacilitySearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectFacilitySearch, projectSearchBody, projectSearchParams); - - if (projectFacilitySearchResponse?.ProjectFacilities && Array.isArray(projectFacilitySearchResponse?.ProjectFacilities) && projectFacilitySearchResponse?.ProjectFacilities?.length > 0) { - return projectFacilitySearchResponse; - } - else { - return null - } - } catch (error: any) { - throwError("PROJECT", 500, "PROJECT_FACILTY_SEARCH_ERROR") - } -} - - -async function fetchProjectStaffWithProjectId(request: any, projectId: any, staffId: any) { - try { - const { tenantId } = request?.body?.parentCampaign || request?.parentCampaign; - const projectSearchBody = { - RequestInfo: request?.body?.RequestInfo || request?.RequestInfo, - ProjectStaff: { - projectId: [ - projectId - ], - staffId: [ - staffId - ] - } - } - - const projectSearchParams = { - tenantId: tenantId, - offset: 0, - limit: 1 - } - logger.info("Project search params " + JSON.stringify(projectSearchParams)) - const projectStaffSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectStaffSearch, projectSearchBody, projectSearchParams); - if (projectStaffSearchResponse?.ProjectStaff && Array.isArray(projectStaffSearchResponse?.ProjectStaff) && projectStaffSearchResponse?.ProjectStaff?.length > 0) { - return projectStaffSearchResponse; - } - else { - return null - } - } catch (error: any) { - throwError("PROJECT", 500, "PROJECT_STAFF_SEARCH_ERROR") - } - -} - -async function delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary(resource: any, messageObject: any, boundaryCode: any, uniqueIdentifier: any, isDelink: boolean) { - const projectResponse = await fetchProjectsWithBoundaryCodeAndReferenceId(boundaryCode, messageObject?.parentCampaign?.tenantId, messageObject?.CampaignDetails?.campaignNumber, messageObject?.RequestInfo); - let matchingProjectObject: any; - if (projectResponse) { - matchingProjectObject = projectResponse?.Project[0]; - } - const matchingProjectId = matchingProjectObject?.id; - if (!matchingProjectId) { - return false; // No matching project found - } - - - if (resource?.type === "facility") { - const projectFacilityResponse = await fetchProjectFacilityWithProjectId(messageObject, matchingProjectId, uniqueIdentifier); - if (projectFacilityResponse) { - if (isDelink) { - await deleteProjectFacilityMapping(messageObject, projectFacilityResponse) - } - return true; - } else { - return false; - } - } - if (resource?.type === 'user') { - const projectStaffResponse = await fetchProjectStaffWithProjectId(messageObject, matchingProjectId, uniqueIdentifier); - if (projectStaffResponse) { - if (isDelink) { - await deleteProjectStaffMapping(messageObject, projectStaffResponse) - } - return true; - } else { - return false; - } - } - else return false; -} - - -async function deleteProjectFacilityMapping(messageObject: any, projectFacilityResponse: any) { - const projectFacilityDeleteBody = { - RequestInfo: messageObject?.RequestInfo, - ProjectFacilities: [ - projectFacilityResponse?.ProjectFacilities[0] - ] - } - try { - await httpRequest(config?.host?.projectHost + config?.paths?.projectFacilityDelete, projectFacilityDeleteBody); - } - catch (error: any) { - throwError("PROJECT", 500, "PROJECT_FACILITY_DELETE_ERROR") - } -} - -async function deleteProjectStaffMapping(messageObject: any, projectStaffResponse: any) { - const projectStaffDeleteBody = { - RequestInfo: messageObject?.RequestInfo, - ProjectStaff: [ - projectStaffResponse?.ProjectStaff[0] - ] - } - try { - await httpRequest(config?.host?.projectHost + config?.paths?.projectStaffDelete, projectStaffDeleteBody); - } - catch (error: any) { - throwError("PROJECT", 500, "PROJECT_STAFF_DELETE_ERROR") - } -} - - -async function getParentAndCurrentFileUrl(mappingObject: any, resource: any, parentResource: any) { - const parentCreateResourceId = parentResource?.createResourceId ? [parentResource.createResourceId] : []; - const parentResourceSearchResponse = await getResourceFromResourceId(mappingObject, parentCreateResourceId, parentResource); - const parentProcessedFileStoreId = parentResourceSearchResponse?.[0]?.processedFilestoreId; - - const currentCreateResourceId = resource?.createResourceId ? [resource.createResourceId] : []; - const currentResourceSearchResponse = await getResourceFromResourceId(mappingObject, currentCreateResourceId, resource); - const currentProcessedFileStoreId = currentResourceSearchResponse?.[0]?.processedFilestoreId; - - const currentFileUrl = await getFileUrl(currentProcessedFileStoreId, mappingObject?.CampaignDetails?.tenantId); - const parentFileUrl = await getFileUrl(parentProcessedFileStoreId, mappingObject?.CampaignDetails?.tenantId); - - return { currentFileUrl, parentFileUrl }; -} - -function findParentResource(resource: any, resourcesArrayFromParentCampaign: any) { - return resourcesArrayFromParentCampaign.find( - (parentResource: any) => parentResource.type === resource.type - ); -} - -async function getHeadersAccordingToWhichWeReorder(parentWorkbook: any, resource: any) { - - // Determine the sheet name dynamically based on resource type - const headerSourceSheetName: any = resource?.type === 'boundaryWithTarget' - ? parentWorkbook.worksheets[2]?.name // Use the third sheet for 'boundaryWithTarget' type - : parentWorkbook.worksheets[1]?.name; // Use the second sheet for other types - - const sheet = parentWorkbook.getWorksheet(headerSourceSheetName); - if (!sheet) { - throw new Error(`Sheet with name "${headerSourceSheetName}" not found`); - } - - // Get the first row (assuming it's the header row) - const headerRow = sheet.getRow(1); - // Get the first row (assuming it's the header row) - if (!headerRow || headerRow.cellCount === 0) { - throw new Error(`Header row is empty in sheet "${headerSourceSheetName}"`); - } - const headers: any = []; - - headerRow.eachCell((cell: any) => { - headers.push(cell.value); // Collect header cell values - }); - - return headers; -} - - - -async function addDataToWorkbook(currentWorkbook: any, parentWorkbook: any, currentFileUrl: any, resource: any, headersAccordingToWhichWeReorder: any) { - const currentSheet = currentWorkbook.worksheets[1]; - if (resource?.type === 'boundaryWithTarget') { - const boundaryWithTargetSheetData = await getTargetSheetData(currentFileUrl, false, false); - const sheetNames = Object.keys(boundaryWithTargetSheetData); // Get sheet names - for (let i = 2; i < sheetNames.length; i++) { // Start from index 2 for the third sheet - const sheetName = sheetNames[i]; - const sheetData = boundaryWithTargetSheetData[sheetName]; - - // Reorder each row in the current sheet's data - const reorderedData = sheetData.map((row: any) => { - // Map each header in `targetHeaders` to the corresponding value in `row`, - // or set to an empty string if the header is missing - return headersAccordingToWhichWeReorder.map((header: any) => row[header] || ""); - }); - - await addConsolidatedDataToSheet(parentWorkbook, sheetName, headersAccordingToWhichWeReorder, reorderedData); - } - } else { - // Perform further processing using the filestoreId - const currentSheetData: any = await getSheetData(currentFileUrl, currentSheet.name, false) - - const reorderedData = currentSheetData.map((row: any) => { - // Map each header in `targetHeaders` to the corresponding value in the row, - // or set to an empty string if the header is missing in the row - return headersAccordingToWhichWeReorder.map((header: any) => row[header] || ""); - }); - - await addConsolidatedDataToSheet(parentWorkbook, currentSheet.name, headersAccordingToWhichWeReorder, reorderedData); - } -} - - -async function finalizeAndUpload(newWorkbook: any, mappingObject: any, resource: any) { - const responseData = await createAndUploadFile(newWorkbook, mappingObject, mappingObject?.CampaignDetails?.tenantId); - const fileStoreId = responseData?.[0]?.fileStoreId; - const resourceDetails = (await getResourceFromResourceId(mappingObject, [resource.createResourceId], resource))[0]; - resourceDetails.processedFilestoreId = fileStoreId; - resourceDetails.processedFileStoreId = resourceDetails.processedFilestoreId; - resourceDetails.processedFilestoreId = undefined; - - const persistMessage: any = { ResourceDetails: resourceDetails }; - await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); -} - - - - -async function processIndividualResource(mappingObject: any, resource: any, resourcesArrayFromParentCampaign: any) { - const parentResource = findParentResource(resource, resourcesArrayFromParentCampaign); - const fileUrls = await getParentAndCurrentFileUrl(mappingObject, resource, parentResource); - - const parentWorkbook = await getExcelWorkbookFromFileURL(fileUrls.parentFileUrl); - const currentWorkbook = await getExcelWorkbookFromFileURL(fileUrls.currentFileUrl) - - const headersAccordingToWhichWeReorder = await getHeadersAccordingToWhichWeReorder(parentWorkbook, resource); - await addDataToWorkbook(currentWorkbook, parentWorkbook, fileUrls?.currentFileUrl, resource, headersAccordingToWhichWeReorder); - - await finalizeAndUpload(parentWorkbook, mappingObject, resource); -} - - -function mergeParentResources(mappingObject: any, resources: any[], resourcesArrayFromParentCampaign: any[]) { - for (const resource of resourcesArrayFromParentCampaign) { - if (!resources.some((r: any) => r.type === resource.type)) { - resources.push(resource); - } - } - mappingObject.CampaignDetails.campaignDetails.resources = resources; -} - -async function processResources(mappingObject: any) { - - const resources = mappingObject?.CampaignDetails?.resources; - const resourcesArrayFromParentCampaign = mappingObject?.parentCampaign?.resources; - - for (const resource of resources) { - try { - await processIndividualResource(mappingObject, resource, resourcesArrayFromParentCampaign); - } catch (error: any) { - throwError("CAMPAIGN", 500, "RESOURCES_CONSOLIDATION_ERROR", - `Error occurred while consolidating resource of type ${resource.type}: ${error.message}`); - } - } - - mergeParentResources(mappingObject, resources, resourcesArrayFromParentCampaign); -} - -async function getResourceFromResourceId(mappingObject: any, createResourceId: any, resource: any) { - const searchCriteria = buildSearchCriteria(mappingObject, createResourceId, resource?.type); - const requestBody = replicateRequest(mappingObject, searchCriteria); - const responseFromDataSearch = await searchDataService(requestBody); - return responseFromDataSearch; -} - - -async function addConsolidatedDataToSheet(parentWorkbook: any, sheetName: string, targetHeaders: string[], reorderedData: any[]) { - // Get or create a worksheet - let sheet = parentWorkbook.getWorksheet(sheetName); - if (!sheet) { - sheet = parentWorkbook.addWorksheet(sheetName); - sheet.addRow(targetHeaders); - } - if (sheet.rowCount > 1) { - // Clear all existing row data starting from the second row - for (let i = 2; i <= sheet.rowCount; i++) { - sheet.getRow(i).values = []; - } - } - - // Overwrite cleared rows with new data - reorderedData.forEach((row, index) => { - const targetRow = sheet.getRow(index + 2); // Start from the second row - targetRow.values = row; // Add the row's values - }); - -} - - -async function getFileUrl(fileStoreId: any, tenantId: any) { - const fileResponse = await httpRequest( - `${config.host.filestore}${config.paths.filestore}/url`, - {}, - { tenantId, fileStoreIds: fileStoreId }, - "get" - ); - - if (!fileResponse || !fileResponse.fileStoreIds || !fileResponse.fileStoreIds[0] || !fileResponse.fileStoreIds[0].url) { - throwError("FILE", 400, "INVALID_FILE"); - } else { - return fileResponse.fileStoreIds[0].url; - } -} - - - - -export { - getParentCampaignObject, - getCreatedResourceIds, - buildSearchCriteria, - fetchFileUrls, - modifyProcessedSheetData, - freezeUnfreezeColumnsForProcessedFile, - getColumnIndexByHeader, - checkAndGiveIfParentCampaignAvailable, - hideColumnsOfProcessedFile, - unhideColumnsOfProcessedFile, - modifyNewSheetData, - validateBoundariesIfParentPresent, - callGenerateWhenChildCampaigngetsCreated, - getBoundariesFromCampaignSearchResponse, - fetchProjectsWithProjectId, - getBoundaryProjectMappingFromParentCampaign, - fetchProjectFacilityWithProjectId, - fetchProjectsWithBoundaryCodeAndReferenceId, - delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary, - processResources -} \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/pollUtils.ts b/health-services/project-factory/src/server/utils/pollUtils.ts deleted file mode 100644 index afba8042988..00000000000 --- a/health-services/project-factory/src/server/utils/pollUtils.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { defaultRequestInfo } from "../api/coreApis"; // Import default request metadata -import { getFormattedStringForDebug, logger } from "./logger"; // Import logger for logging information and errors -import { createDataService, downloadDataService, searchDataService } from "../service/dataManageService"; -import { throwError } from "./genericUtils"; - -/** - * Downloads a campaign template based on campaign ID, tenant ID, type, and hierarchy. - * @param campaignId The unique identifier for the campaign. - * @param tenantId The tenant identifier for which the template is downloaded. - * @param type The type of the template to be downloaded. - * @param hierarchy The hierarchy type associated with the campaign. - * @returns The response containing the template download details. - */ -export const downloadTemplate = async ( - campaignId: string, - tenantId: string, - type: string, - hierarchy: string -) => { - const searchBody = { - ...defaultRequestInfo, // Include default request metadata - }; - - const params = { - tenantId: tenantId, // Tenant information for the request - type: type, // Specify the template type - hierarchyType: hierarchy, // Specify the hierarchy type - campaignId: campaignId, // Campaign identifier - }; - - logger.info( - `Received a request to download the template for campaign ID: ${campaignId} & type: ${type} ` - ); - const request: any = { - body: { ...searchBody }, - query: { ...params } - } - - const downloadResponse: any = await downloadDataService(request); - - logger.debug(`Received response : ${getFormattedStringForDebug(downloadResponse)}`); - return downloadResponse; // Return the API response containing template details -}; - -/** - * Polls a function at regular intervals until a condition is met or the maximum retries are reached. - * @param functionToBePolledFor The function to be executed for polling. - * @param conditionForTermination A callback function that evaluates whether polling should stop. - * @param pollInterval The interval (in milliseconds) between each poll attempt. Default is 2000ms. - * @param maxRetries The maximum number of retries before terminating polling. Default is 50. - * @returns A promise that resolves with the function response if the condition is met, or rejects if retries are exhausted. - */ -const pollForTemplateGeneration = async ( - functionToBePolledFor: Function, - conditionForTermination: Function, - pollInterval: number = 2500, - maxRetries: number = 20 -) => { - let retries = 0; // Initialize the retry counter - logger.info("received a request for Polling "); - if (!functionToBePolledFor || !conditionForTermination) { - return null; - } - logger.info("request was valid so Polling "); - - return new Promise((resolve, reject) => { - const poll = async () => { - try { - if (retries >= maxRetries) { - // Reject if maximum retries are reached - reject(new Error("Max retries reached")); - return; - } - - const functionResponse = await functionToBePolledFor(); // Execute the polling function - - if (conditionForTermination(functionResponse)) { - // Check if the termination condition is met - logger.info("Polling completed"); - resolve(functionResponse); - return; - } else { - // Increment retries and continue polling after the specified interval - retries++; - logger.info("Polling continuing"); - setTimeout(poll, pollInterval); - } - } catch (error) { - // Handle errors by retrying after the specified interval - retries++; - setTimeout(poll, pollInterval); - } - }; - - // Start polling - poll().catch(reject); - - // Set a timeout to ensure the entire polling operation doesn't exceed a maximum duration - const timeoutDuration = (maxRetries + 1) * pollInterval; - setTimeout(() => { - if (retries < maxRetries) { - logger.error("Polling timeout: Max retries reached"); - reject(new Error("Polling timeout: Max retries reached")); - } - }, timeoutDuration); - }); -}; - - - -const conditionForTermination = (downloadResponse: any) => { - logger.info(`current status ${downloadResponse?.[0]?.status}`) - return downloadResponse?.[0]?.status === "completed" && downloadResponse?.[0]?.fileStoreid; -} - -const conditionForTermination2 = (downloadResponse: any) => { - logger.info(`current status ${downloadResponse?.[0]?.status}`) - return downloadResponse?.[0]?.status === "completed" && downloadResponse?.[0]?.processedFilestoreId; -} - -export const createAndPollForCompletion = async (request: any) => { - try { - // Step 1: Create data - logger.info("Creating data..."); - const resourceDetails = await createDataService(request); - const resourceId = resourceDetails?.id; - - if (!resourceId) { - throwError("DATA", 500, "DATA_CREATE_ERROR", `Failed to retrieve resource ID from creation response for type ${request?.body?.ResourceDetails?.type}`); - } - - logger.info(`Created resource with ID: ${resourceId} of type ${request?.body?.ResourceDetails?.type}`); - - // Step 2: Poll for completion - const polledResponse = await pollForTemplateGeneration( - () => searchData(resourceId, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.type), - conditionForTermination2, - 3000, - 30 - ); - - logger.info("Polling completed successfully", polledResponse); - return polledResponse; - } catch (error: any) { - logger.error("Error during creation or polling", error); - throw error; - } -}; - - - -async function searchData(resourceId: any, tenantId: any, type: any) { - const SearchCriteria = { - id: [resourceId], - tenantId: tenantId, - type: type - }; - const searchBody = { ...defaultRequestInfo, SearchCriteria } - const request: any = { - body: { ...searchBody } - } - - const searchResponse: any = await searchDataService(request); - return searchResponse; -} - - - -export const getTheGeneratedResource = async ( - campaignId: string, - tenantId: string, - type: string, - hierarchy: string -) => { - try { - // Await the response from polling for template generation - const polledResponse: any = await pollForTemplateGeneration( - () => downloadTemplate(campaignId, tenantId, type, hierarchy), - conditionForTermination - ); - - // Log the polled response for debugging - logger.debug(polledResponse); - logger.debug(`polledResponse : ${getFormattedStringForDebug(polledResponse)}`); - - // Return the fileStoreid from the response, ensuring the correct format - return polledResponse?.[0]?.fileStoreid; - - } catch (error: any) { - // Log any error that occurs during polling or processing - logger.error(`Error while fetching the generated resource: ${error?.message}`); - } -} diff --git a/health-services/project-factory/src/server/utils/processTrackUtils.ts b/health-services/project-factory/src/server/utils/processTrackUtils.ts index 6d80346825f..d822e28fded 100644 --- a/health-services/project-factory/src/server/utils/processTrackUtils.ts +++ b/health-services/project-factory/src/server/utils/processTrackUtils.ts @@ -1,224 +1,52 @@ import config from './../config'; -import { produceModifiedMessages } from "../kafka/Producer";; +import { produceModifiedMessages } from '../kafka/Listener'; import { v4 as uuidv4 } from 'uuid'; import { executeQuery } from './db'; -import { processTrackForUi, processTrackStatuses, processTrackTypes } from '../config/constants'; -import { logger } from './logger'; - -async function getProcessDetails(id: string, type?: string): Promise { - let query: string; - const values: any[] = [id]; - - logger.info(`Fetching process details for campaignId: ${id}${type ? `, type: ${type}` : ''}`); - - if (type) { - query = ` - SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_PROCESS_TABLE_NAME} - WHERE campaignid = $1 AND type = $2 - ORDER BY lastmodifiedtime ASC; - `; - values.push(type); - } else { - query = ` - SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_PROCESS_TABLE_NAME} - WHERE campaignid = $1 - ORDER BY lastmodifiedtime ASC; - `; - } +async function getProcessDetails(id: any): Promise { + const query = `SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_PROCESS_TABLE_NAME} WHERE id = $1`; + const values = [id]; const queryResponse = await executeQuery(query, values); - - if (queryResponse.rows.length === 0) { - logger.info('No process details found'); - return []; - } - const uiSet = new Set(processTrackForUi.map((item: any) => item)); - return queryResponse.rows.map((result: any) => ({ - id: result.id, - campaignId: result.campaignid, - type: result.type, - status: result.status, - showInUi: uiSet.has(result.type), - details: result.details, - additionalDetails: result.additionaldetails, - createdTime: parseInt(result.createdtime, 10), - lastModifiedTime: parseInt(result.lastmodifiedtime, 10), - })); + return queryResponse.rows[0]; // Assuming only one row is expected } async function persistTrack( - campaignId: string, - type: string, - status: string, - details?: Record, - additionalDetails?: Record -): Promise { - if (!campaignId) { - logger.info('campaignId is missing, aborting persistTrack'); - return; - } - - logger.info(`Persisting track for campaignId: ${campaignId}, type: ${type}, status: ${status}`); - - if (type == processTrackTypes.error) { - await handleFailedStatus(campaignId, type, status, details, additionalDetails); - } else { - await handleNonFailedStatus(campaignId, type, status, details, additionalDetails); - } -} - -// Handles the case when the status is 'failed' -async function handleFailedStatus( - campaignId: string, - type: string, - status: string, - details?: Record, - additionalDetails?: Record -): Promise { - const processDetailsArray = await getProcessDetails(campaignId); - const inProgressProcessDetails = processDetailsArray.filter((processDetail: any) => processDetail.status === processTrackStatuses.inprogress); - const toBeCompletedProcessDetails = processDetailsArray.filter((processDetail: any) => processDetail.status === processTrackStatuses.toBeCompleted); - const failedStatusArray = processDetailsArray.filter((processDetail: any) => processDetail.status === processTrackStatuses.failed); - if (failedStatusArray.length > 0) { - logger.info('Process already failed, nothing to persist'); - await updateToBeCompletedProcess(toBeCompletedProcessDetails, status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); - return; - } - if (inProgressProcessDetails.length > 0) { - logger.info('Generic fail occured so changing the lastest inprogress status to failed'); - await updateAndProduceMessage(inProgressProcessDetails[inProgressProcessDetails.length - 1], status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); - } else { - logger.info('No inprogress process found, creating a new processDetail to failed'); - await createAndProduceNewProcessDetail(campaignId, type, status, details, additionalDetails, config?.kafka?.KAFKA_SAVE_PROCESS_TRACK_TOPIC); - } - await updateToBeCompletedProcess(toBeCompletedProcessDetails, status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); -} - -async function updateToBeCompletedProcess( - processDetailsArray: any[], - status: string, - details?: Record, - additionalDetails?: Record, - kafkaTopic?: string) { - details = details || {}, - details.error = "HCM_PROCESS_TRACK_PREVIOUS_PROCESS_FAILED" - if (processDetailsArray.length > 0) { - for (let i = 0; i < processDetailsArray.length; i++) { - await updateAndProduceMessage(processDetailsArray[i], status, details, additionalDetails, kafkaTopic); - } - } -} - -// Handles the case when the status is not 'failed' -async function handleNonFailedStatus( - campaignId: string, - type: string, - status: string, - details?: Record, - additionalDetails?: Record + campaignId: any, + type: any, + status: any, + details?: any, + additionalDetails?: any, + id?: any ): Promise { - const processDetailsArray = await getProcessDetails(campaignId, type); + let processDetails: any; - if (processDetailsArray.length === 0) { - logger.info('No process details found, nothing to persist'); - return; + if (id) { + processDetails = await getProcessDetails(id); + details = { ...processDetails?.details, ...details }; + additionalDetails = { ...processDetails?.additionalDetails, ...additionalDetails }; } - updateAndProduceMessage(processDetailsArray[0], status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); -} - -// Updates an existing process detail and produces the message -async function updateAndProduceMessage( - processDetails: any, - status: string, - details?: Record, - additionalDetails?: Record, - kafkaTopic?: string -) { - updateProcessDetails(processDetails, processDetails.type, status, details, additionalDetails); - const produceMessage: any = { processDetails }; - await produceModifiedMessages(produceMessage, kafkaTopic); -} + const processId = id || uuidv4(); + const createdTime = Date.now(); + const lastModifiedTime = Date.now(); -// Creates a new process detail and produces the message -async function createAndProduceNewProcessDetail( - campaignId: string, - type: string, - status: string, - details?: Record, - additionalDetails?: Record, - kafkaTopic?: string -) { - const currentTime = Date.now(); - const processDetail: any = { - id: uuidv4(), + processDetails = { + id: processId, campaignId, type, status, - createdTime: currentTime, - lastModifiedTime: currentTime, - details: details || {}, - additionalDetails: additionalDetails || {}, + details, + additionalDetails, + createdTime, + lastModifiedTime }; - updateProcessDetails(processDetail, type, status, details, additionalDetails); - const produceMessage: any = { processDetails: [processDetail] }; - await produceModifiedMessages(produceMessage, kafkaTopic); -} - - -function updateProcessDetails( - processDetails: any, - type: string, - status: string, - details?: any, - additionalDetails?: any -) { - processDetails.lastModifiedTime = Date.now(); - processDetails.details = { ...processDetails.details, ...details }; - processDetails.additionalDetails = { ...processDetails.additionalDetails, ...additionalDetails }; - processDetails.type = type; - processDetails.status = status; -} - -async function createProcessTracks(campaignId: string) { - logger.info(`Creating process tracks for campaignId: ${campaignId}`); - - const processDetailsArray: any[] = []; - - Object.keys(processTrackTypes).forEach(key => { - const type: any = (processTrackTypes as any)[key]; - const currentTime = Date.now(); - if (type != processTrackTypes.error) { - const processDetail: any = { - id: uuidv4(), - campaignId, - type, - status: processTrackStatuses.toBeCompleted, - createdTime: currentTime, - lastModifiedTime: currentTime, - details: {}, - additionalDetails: {} - }; - processDetailsArray.push(processDetail); - } - }); - - logger.info(`Created ${processDetailsArray.length} process tracks`); - const produceMessage: any = { processDetails: processDetailsArray } - await produceModifiedMessages(produceMessage, config?.kafka?.KAFKA_SAVE_PROCESS_TRACK_TOPIC); -} - -function getOrderedDetailsArray(toBeCompletedArray: any[]) { - const order = Object.values(processTrackTypes); - return toBeCompletedArray.sort((a, b) => order.indexOf(a.type) - order.indexOf(b.type)); -} + const produceObject: any = { + processDetails + }; -export function modifyProcessDetails(processDetailsArray: any[]) { - const toBeCompletedArray = processDetailsArray.filter((item: any) => item.status === processTrackStatuses.toBeCompleted); - const orderedToBeCompletedArray = getOrderedDetailsArray(toBeCompletedArray); - const otherArray = processDetailsArray.filter((item: any) => item.status !== processTrackStatuses.toBeCompleted); - return otherArray.concat(orderedToBeCompletedArray); + const topic = id ? config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC : config?.kafka?.KAFKA_SAVE_PROCESS_TRACK_TOPIC; + produceModifiedMessages(produceObject, topic); } -export { persistTrack, getProcessDetails, createProcessTracks }; +export { persistTrack }; \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/redisUtils.ts b/health-services/project-factory/src/server/utils/redisUtils.ts index 320705df1d6..f62177928d9 100644 --- a/health-services/project-factory/src/server/utils/redisUtils.ts +++ b/health-services/project-factory/src/server/utils/redisUtils.ts @@ -1,6 +1,5 @@ import Redis from "ioredis"; import config from "../config"; -import { logger } from "./logger"; const redis = new Redis({ host: config.host.redisHost, @@ -19,59 +18,12 @@ const redis = new Redis({ async function checkRedisConnection(): Promise { try { - if (config?.cacheValues?.cacheEnabled) { - await redis.ping(); - } + await redis.ping(); return true; - } catch (error) { console.error("Redis connection error:", error); return false; } } -// Listen for the 'connect' event -redis.on('connect', () => { - logger.info(`Successfully connected to Redis! host :: ${config.host.redisHost} & port :: ${config.cacheValues.redisPort}`); - // You can add additional code here to perform actions after a successful connection -}); - -// Listen for errors -redis.on('error', (err) => { - logger.info(`failed connecting to Redis! host :: ${config.host.redisHost} & port :: ${config.cacheValues.redisPort}`); - logger.error("Redis connection error:", err); -}); - - - -async function deleteRedisCacheKeysWithPrefix(prefix: any) { - try { - // Use SCAN instead of KEYS to avoid performance issues - let cursor = '0'; - let keysToDelete: any = []; - - do { - const result = await redis.scan(cursor, 'MATCH', `${prefix}*`, 'COUNT', '100'); - cursor = result[0]; - const keys = result[1]; - - if (keys.length > 0) { - keysToDelete = keysToDelete.concat(keys); - logger.info("Cache keys found to be deleted: " + keys); - } - } while (cursor !== '0'); - - if (keysToDelete.length > 0) { - await redis.del(...keysToDelete); - logger.info(`Deleted keys with prefix "${prefix}":`, keysToDelete); - } else { - logger.info(`No keys found with prefix "${prefix}"`); - } - } catch (error) { - logger.info("Error deleting keys:", error); - throw error; - } -} - - -export { redis, checkRedisConnection, deleteRedisCacheKeysWithPrefix }; +export { redis, checkRedisConnection }; diff --git a/health-services/project-factory/src/server/utils/request.ts b/health-services/project-factory/src/server/utils/request.ts index 88ea55b52c3..ef23426cc0e 100644 --- a/health-services/project-factory/src/server/utils/request.ts +++ b/health-services/project-factory/src/server/utils/request.ts @@ -47,7 +47,6 @@ const cacheEnabled = config.cacheValues.cacheEnabled; // Variable to indicate wh /** * Used to Make API call through axios library - * @author jagankumar-egov * * @param {string} _url - The URL to make the HTTP request to * @param {Object} _requestBody - The request body @@ -125,10 +124,6 @@ const httpRequest = async ( } return sendStatusCode ? { ...response.data, statusCode: responseStatus } : response.data; } - else{ - logger.warn(`Error occurred while making request to ${getServiceName(_url)}: with error response ${JSON.stringify(response.data)}`); - return sendStatusCode ? { ...response.data, statusCode: responseStatus } : response.data; - } } catch (error: any) { const errorResponse = error?.response; logger.error( @@ -153,50 +148,25 @@ const httpRequest = async ( errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] } )}` ); - if ( - retry || - (config.values.autoRetryIfHttpError && - config.values.autoRetryIfHttpError?.includes( - errorResponse?.data?.Errors?.[0]?.code - )) - ) { - logger.info( - `retrying the failed api call since retry is enabled or error is equal to configured ${config.values.autoRetryIfHttpError}` - ); + if (retry) { attempt++; if (attempt >= maxAttempts) { if (dontThrowError) { - logger.warn( - `Maximum retry attempts reached for httprequest with url ${_url}` - ); - return ( - errorResponse?.data || { - Errors: [{ code: error.message, description: error.stack }], - } - ); + logger.warn(`Maximum retry attempts reached for httprequest with url ${_url}`); + return errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] }; } else { throwTheHttpError(errorResponse, error, _url); } } - logger.warn( - `Waiting for 20 seconds before retrying httprequest with url ${_url}` - ); + logger.warn(`Waiting for 20 seconds before retrying httprequest with url ${_url}`); await new Promise((resolve) => setTimeout(resolve, 20000)); } else if (dontThrowError) { logger.warn( - `Error occurred while making request to ${getServiceName( - _url - )}: returning error response ${JSON.stringify( - errorResponse?.data || { - Errors: [{ code: error.message, description: error.stack }], - } + `Error occurred while making request to ${getServiceName(_url)}: returning error response ${JSON.stringify( + errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] } )}` ); - return ( - errorResponse?.data || { - Errors: [{ code: error.message, description: error.stack }], - } - ); + return errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] }; } else { throwTheHttpError(errorResponse, error, _url); } diff --git a/health-services/project-factory/src/server/utils/targetUtils.ts b/health-services/project-factory/src/server/utils/targetUtils.ts deleted file mode 100644 index 7e102feb6d8..00000000000 --- a/health-services/project-factory/src/server/utils/targetUtils.ts +++ /dev/null @@ -1,137 +0,0 @@ -import config from '../config' -import { checkIfSourceIsMicroplan, getConfigurableColumnHeadersBasedOnCampaignType, getLocalizedName } from './campaignUtils'; -import _ from 'lodash'; -import { replicateRequest } from './genericUtils'; -import { callGenerate } from './generateUtils'; - - -async function generateDynamicTargetHeaders(request: any, campaignObject: any, localizationMap?: any) { - const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); - let headerColumnsAfterHierarchy: any; - if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0 && !isSourceMicroplan) { - const modifiedUniqueDeliveryConditions = modifyDeliveryConditions(campaignObject.deliveryRules); - headerColumnsAfterHierarchy = generateTargetColumnsBasedOnDeliveryConditions(modifiedUniqueDeliveryConditions, localizationMap); - - } - else { - headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request); - headerColumnsAfterHierarchy.shift(); - } - return headerColumnsAfterHierarchy; -} - - -function modifyDeliveryConditions(dataa: any[]): any { - let resultSet = new Set(); - dataa.forEach((delivery) => { - const conditions = delivery.conditions; - let newArray: any[] = []; - - conditions.forEach((item: any) => { - const existingIndex = newArray.findIndex( - (element) => element.attribute.code === item.attribute - ); - - if (existingIndex !== -1) { - const existingItem = newArray[existingIndex]; - // Combine conditions if necessary - if (existingItem.operator.code !== item.operator.code) { - newArray[existingIndex] = { - attribute: existingItem.attribute, - operator: { code: "IN_BETWEEN" }, - toValue: - existingItem.value && item.value ? Math.max(existingItem.value, item.value) : null, - fromValue: - existingItem.value && item.value ? Math.min(existingItem.value, item.value) : null - }; - } - } else { - // If attribute does not exist in newArray, add the item - newArray.push({ - attribute: { code: item.attribute }, - operator: { code: item.operator }, - value: item.value - }); - } - }); - newArray.map((element: any) => { - const stringifiedElement = JSON.stringify(element); // Convert object to string - resultSet.add(stringifiedElement); - }) - }); - return resultSet; -} - - -function generateTargetColumnsBasedOnDeliveryConditions(uniqueDeliveryConditions: any, localizationMap?: any) { - const targetColumnsBasedOnDeliveryConditions: string[] = []; - uniqueDeliveryConditions.forEach((str: any, index: number) => { - const uniqueDeliveryConditionsObject = JSON.parse(str); // Parse JSON string into object - const targetColumnString = createTargetString(uniqueDeliveryConditionsObject, localizationMap); - targetColumnsBasedOnDeliveryConditions.push(targetColumnString); - }); - if (targetColumnsBasedOnDeliveryConditions.length > 18) { - targetColumnsBasedOnDeliveryConditions.splice(18); - targetColumnsBasedOnDeliveryConditions.push(getLocalizedName("OTHER_TARGETS", localizationMap)); - } - return targetColumnsBasedOnDeliveryConditions; -} - -function createTargetString(uniqueDeliveryConditionsObject: any, localizationMap?: any) { - let targetString: any; - const prefix = getLocalizedName("HCM_ADMIN_CONSOLE_TARGET_SMC", localizationMap); - const attributeCode = getLocalizedName(uniqueDeliveryConditionsObject.attribute.code.toUpperCase(), localizationMap); - const operatorMessage = getLocalizedName(uniqueDeliveryConditionsObject.operator.code, localizationMap); - const localizedFROM = getLocalizedName("FROM", localizationMap); - const localizedTO = getLocalizedName("TO", localizationMap); - if (uniqueDeliveryConditionsObject.operator.code === 'IN_BETWEEN') { - targetString = `${prefix} ${attributeCode} ${localizedFROM} ${uniqueDeliveryConditionsObject.fromValue} ${localizedTO} ${uniqueDeliveryConditionsObject.toValue}`; - } else { - targetString = `${prefix} ${attributeCode} ${operatorMessage} ${uniqueDeliveryConditionsObject.value}`; - } - return targetString; -} - -async function updateTargetColumnsIfDeliveryConditionsDifferForSMC(request: any) { - const existingCampaignDetails = request?.body?.ExistingCampaignDetails; - if (existingCampaignDetails) { - if (isDynamicTargetTemplateForProjectType(request?.body?.CampaignDetails?.projectType) && config?.isCallGenerateWhenDeliveryConditionsDiffer && !_.isEqual(existingCampaignDetails?.deliveryRules, request?.body?.CampaignDetails?.deliveryRules)) { - const newRequestBody = { - RequestInfo: request?.body?.RequestInfo, - Filters: { - boundaries: request?.body?.boundariesCombined - } - }; - - const { query } = request; - const params = { - tenantId: request?.body?.CampaignDetails?.tenantId, - forceUpdate: 'true', - hierarchyType: request?.body?.CampaignDetails?.hierarchyType, - campaignId: request?.body?.CampaignDetails?.id - }; - - const newParamsBoundary = { ...query, ...params, type: "boundary" }; - const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); - await callGenerate(newRequestBoundary, "boundary", true); - } - } -} - -function isDynamicTargetTemplateForProjectType(projectType: string) { - const projectTypesFromConfig = config?.enableDynamicTemplateFor; - const projectTypesArray = projectTypesFromConfig ? projectTypesFromConfig.split(',') : []; - return projectTypesArray.includes(projectType); -} - - - - - -export { - modifyDeliveryConditions, - generateTargetColumnsBasedOnDeliveryConditions, - generateDynamicTargetHeaders, - updateTargetColumnsIfDeliveryConditionsDifferForSMC, - isDynamicTargetTemplateForProjectType -}; diff --git a/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts index 64aa3cacef5..a2528ce515d 100644 --- a/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts +++ b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts @@ -4,7 +4,6 @@ import { } from "../localisationUtils"; import Localisation from "../../controllers/localisationController/localisation.controller"; import { logger } from "../logger"; -import config from "../../config"; /** * Transforms boundary map into localisation messages and creates localisation entries. @@ -12,114 +11,36 @@ import config from "../../config"; * @param hierarchyType - Type of hierarchy for the localisation module. * @param request - Request object containing necessary information. */ - -export const transformAndCreateLocalisation = async ( +export const transformAndCreateLocalisation = ( boundaryMap: any, request: any ) => { - const CHUNK_SIZE = config.localisation.localizationChunkSizeForBoundaryCreation - - try { - const { tenantId, hierarchyType } = request?.body?.ResourceDetails || {}; + const { tenantId, hierarchyType } = request?.body?.ResourceDetails || {}; - // Get localisation module name based on hierarchy type - const module = getLocalisationModuleName(hierarchyType); + // Get localisation module name based on hierarchy type + const module = getLocalisationModuleName(hierarchyType); - // Get locale from request object - const locale = getLocaleFromRequest(request); + // Get locale from request object + const locale = getLocaleFromRequest(request); - // Array to store localisation messages - const localisationMessages: any[] = []; + // Array to store localisation messages + const localisationMessages: any = []; - // Iterate over boundary map to transform into localisation messages - boundaryMap.forEach((code: string, boundary: any) => { - if(boundary.value !== '' && boundary.value !== undefined){ - localisationMessages.push({ - code, - message: boundary.value, - module, - locale, - }); - } + // Iterate over boundary map to transform into localisation messagess + boundaryMap.forEach((code: string, boundary: any) => { // Add transformed message to localisation messages array + localisationMessages.push({ + code, + message: boundary.value, + module, + locale, }); - logger.info("Localisation message transformed successfully from the boundary map"); - - // Call the chunk upload function - await uploadInChunks(localisationMessages, CHUNK_SIZE, tenantId, request); - - logger.info("All chunks uploaded successfully"); - - } catch (error) { - logger.error("Error during transformation and localisation creation:", error); - throw error; // You can further handle this error (e.g., send failure response to client) - } -} - -const uploadInChunks = async (messages: any, chunkSize: any, tenantId: any, request: any) => { - // Check if messages is a valid array and chunkSize is a positive number - if (!Array.isArray(messages) || messages.length === 0) { - logger.error("Invalid or empty messages array provided"); - return; - } - if (typeof chunkSize !== 'number' || chunkSize <= 0) { - logger.error("Invalid chunkSize provided"); - return; - } - const MAX_RETRIES = 3; // Maximum number of retries for a chunk - // Break the messages array into chunks - for (let i = 0; i < messages.length; i += chunkSize) { - let retries = 0; - let success = false; - const chunk = messages.slice(i, i + chunkSize); - logger.info(`Total messages count ${messages?.length}`); - while (retries <= MAX_RETRIES) { - try { - logger.info(`Uploading chunk ${Math.floor(i / chunkSize) + 1}/${Math.ceil(messages.length / chunkSize)} of size ${chunkSize}`); - - // Check if tenantId and request are defined - if (!tenantId || !request) { - throw new Error("tenantId or request is not defined"); - } - - // Instantiate localisation controller - const localisation = Localisation.getInstance(); - - // Upload the current chunk - await localisation.createLocalisation(chunk, tenantId, request); - - // wait for 3 second - const waitTime = config.localisation.localizationWaitTimeInBoundaryCreation - logger.info(`Waiting for ${waitTime / 1000} seconds after each localisation chunk`); - await new Promise((resolve) => setTimeout(resolve, waitTime)); - await localisation.cacheBurst(); - - logger.info(`Successfully uploaded chunk ${Math.floor(i / chunkSize) + 1}`); - success = true; // Mark as successful - break; - } catch (error: any) { - retries += 1; - logger.info(`Retrying chunk ${Math.floor(i / chunkSize) + 1}, Attempt ${retries}`); - logger.error( - `Error uploading chunk ${Math.floor(i / chunkSize) + 1}, Attempt ${retries}: ${error.message}` - ); - - // If retries are exhausted, log failure and move on - if (retries > MAX_RETRIES) { - logger.error( - `Failed to upload chunk ${Math.floor(i / chunkSize) + 1} after ${MAX_RETRIES} retries` - ); - } - - // Optional: Add a delay between retries - await new Promise((resolve) => setTimeout(resolve, 1000)); - } - } - if (!success) { - logger.warn(`Skipping chunk ${Math.floor(i / chunkSize) + 1} after exhausting retries`); - } - } - logger.info("Finished processing all chunks"); -}; + }) + logger.info("localisation message transformed successfully from the boundary map") + // Instantiate localisation controller + const localisation = Localisation.getInstance(); + // Call method to create localisation entries + localisation.createLocalisation(localisationMessages, tenantId,request); + }; diff --git a/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts b/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts index c8cddff7a18..e279306f7ce 100644 --- a/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts +++ b/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts @@ -54,40 +54,32 @@ const defaultProjectType: any = { Convert campaign details to project details enriched with campaign information. */ export const projectTypeConversion = ( + projectType: any = {}, campaignObject: any = {} ) => { const deliveryRules = campaignObject.deliveryRules; - // const resources = getUniqueArrayByProductVariantId(deliveryRules.flatMap((e: { products: any }) => - // [...e.products].map((ele, ind) => ({ - // isBaseUnitVariant: ind == 0, - // productVariantId: ele.value, - // })) - // )); -// /* Temporay fix for project creation of LLIN since the structure of delivery rules is getting changed */ -// const resources = getUniqueArrayByProductVariantId(deliveryRules.flatMap((e:any) => -// [...e.deliveries].map((ele, ind) => ({ -// isBaseUnitVariant: ind == 0, -// productVariantId: ele.deliveryRules?.[0]?.products?.[0]?.value, -// })) -// )); -// const minAndMaxAge = getMinAndMaxAge(deliveryRules); -// var newProjectType = { -// ...projectType, -// validMinAge: minAndMaxAge?.min, -// validMaxAge: minAndMaxAge?.max, -// name: campaignObject.campaignName, -// resources, -// }; -// /*Handled the logics for the SMC Project Type */ -// if (projectType.code == "MR-DN") { -// newProjectType["cycles"] = transformData(deliveryRules); -// } -// logger.debug( -// "transformed projectType : " + getFormattedStringForDebug(newProjectType) -// ); - /* since the structure of delivery rules is getting changed so returning back the same delivery rules */ - - return deliveryRules?.[0] || defaultProjectType?.["LLIN-mz"]; + const resources = getUniqueArrayByProductVariantId(deliveryRules.flatMap((e: { products: any }) => + [...e.products].map((ele, ind) => ({ + isBaseUnitVariant: ind == 0, + productVariantId: ele.value, + })) + )); + const minAndMaxAge = getMinAndMaxAge(deliveryRules); + var newProjectType = { + ...projectType, + validMinAge: minAndMaxAge?.min, + validMaxAge: minAndMaxAge?.max, + name: campaignObject.campaignName, + resources, + }; + /*Handled the logics for the SMC Project Type */ + if (projectType.code == "MR-DN") { + newProjectType["cycles"] = transformData(deliveryRules); + } + logger.debug( + "transformed projectType : " + getFormattedStringForDebug(newProjectType) + ); + return newProjectType; }; /* Enrich project details from campaign details. @@ -102,7 +94,10 @@ export const enrichProjectDetailsFromCampaignDetails = ( logger.debug( "project type : " + getFormattedStringForDebug(projectTypeObject) ); - const defaultProject = projectTypeConversion( CampaignDetails); + const defaultProject = + projectTypeObject || + defaultProjectType?.[projectType] || + defaultProjectType?.["MR-DN"]; return [ { tenantId, @@ -111,11 +106,11 @@ export const enrichProjectDetailsFromCampaignDetails = ( endDate, projectSubType: projectType, department: defaultProject?.group, - description:`${defaultProject?.name}, disease ${defaultProject?.group} campaign created through Admin Console with Campaign Id as ${CampaignDetails?.campaignNumber}`, + description: defaultProject?.name, projectTypeId: defaultProject?.id, name: campaignName, additionalDetails: { - projectType: defaultProject, + projectType: projectTypeConversion(defaultProject, CampaignDetails), }, }, ]; @@ -123,7 +118,7 @@ export const enrichProjectDetailsFromCampaignDetails = ( /* construct max and min age */ -export const getMinAndMaxAge = (deliveries = []) => { +const getMinAndMaxAge = (deliveries = []) => { // Flatten the conditions arrays from all delivery objects and filter to keep only 'Age' attributes const ageConditions = deliveries .flatMap((e: any) => e?.conditions) @@ -286,7 +281,7 @@ const getRequiredCondition = (conditions: Condition[]): string => { }; // Transformation function -export const transformData = (input: DeliveryItem[]): TransformedCycle[] => { +const transformData = (input: DeliveryItem[]): TransformedCycle[] => { const groupedByCycle = input.reduce>((acc, item) => { const { cycleNumber, deliveryNumber, deliveryType, products, conditions,startDate,endDate } = item; diff --git a/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts b/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts index 7e5391847fb..783fb22edd8 100644 --- a/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts +++ b/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts @@ -39,8 +39,6 @@ export const campaignDetailsTransformer = (dbRows: any[] = []) => { status: row?.status, action: row?.action, campaignNumber: row?.campaignnumber, - isActive: row?.isactive, - parentId: row?.parentid, campaignName: row?.campaignname, projectType: row?.projecttype, hierarchyType: row?.hierarchytype, diff --git a/health-services/project-factory/src/server/validators/campaignValidators.ts b/health-services/project-factory/src/server/validators/campaignValidators.ts index c166daddf89..cddd2c9958a 100644 --- a/health-services/project-factory/src/server/validators/campaignValidators.ts +++ b/health-services/project-factory/src/server/validators/campaignValidators.ts @@ -2,11 +2,11 @@ import createAndSearch from "../config/createAndSearch"; import config from "../config"; import { getFormattedStringForDebug, logger } from "../utils/logger"; import { defaultheader, httpRequest } from "../utils/request"; -import { getCampaignSearchResponse, getHeadersOfBoundarySheet, getHierarchy, handleResouceDetailsError } from "../api/campaignApis"; +import { getHeadersOfBoundarySheet, getHierarchy, handleResouceDetailsError } from "../api/campaignApis"; import { campaignDetailsSchema } from "../config/models/campaignDetails"; import Ajv from "ajv"; import { getDifferentDistrictTabs, getLocalizedHeaders, getLocalizedMessagesHandler, getMdmsDataBasedOnCampaignType, replicateRequest, throwError } from "../utils/genericUtils"; -import { createBoundaryMap, enrichInnerCampaignDetails, generateProcessedFileAndPersist, getFinalValidHeadersForTargetSheetAsPerCampaignType, getLocalizedName } from "../utils/campaignUtils"; +import { createBoundaryMap, generateProcessedFileAndPersist, getFinalValidHeadersForTargetSheetAsPerCampaignType, getLocalizedName } from "../utils/campaignUtils"; import { validateBodyViaSchema, validateCampaignBodyViaSchema, validateHierarchyType } from "./genericValidator"; import { searchCriteriaSchema } from "../config/models/SearchCriteria"; import { searchCampaignDetailsSchema } from "../config/models/searchCampaignDetails"; @@ -20,13 +20,8 @@ import { searchProjectTypeCampaignService } from "../service/campaignManageServi import { campaignStatuses, resourceDataStatuses } from "../config/constants"; import { getBoundaryColumnName, getBoundaryTabName } from "../utils/boundaryUtils"; import addAjvErrors from "ajv-errors"; -import { generateTargetColumnsBasedOnDeliveryConditions, isDynamicTargetTemplateForProjectType, modifyDeliveryConditions } from "../utils/targetUtils"; -import { getBoundariesFromCampaignSearchResponse, validateBoundariesIfParentPresent } from "../utils/onGoingCampaignUpdateUtils"; -import { validateExtraBoundariesForMicroplan, validateFacilityBoundaryForLowestLevel, validateLatLongForMicroplanCampaigns, validatePhoneNumberSheetWise, validateTargetsForMicroplanCampaigns, validateUniqueSheetWise, validateUserForMicroplan } from "./microplanValidators"; -import { produceModifiedMessages } from "../kafka/Producer"; -import { planConfigSearch, planFacilitySearch } from "../utils/microplanUtils"; -import { getPvarIds } from "../utils/campaignMappingUtils"; -import { fetchProductVariants } from "../api/healthApis"; + + @@ -88,9 +83,147 @@ async function fetchBoundariesFromCampaignDetails(request: any) { return responseBoundaries; } -function validateTargetForNormalCampaigns(data: any, errors: any, localizedTargetColumnNames: any, localizationMap?: { [key: string]: string }) { +// Compares unique boundaries with response boundaries and throws error for missing codes. +function compareBoundariesWithUnique(uniqueBoundaries: any[], responseBoundaries: any[], request: any) { + // Extracts boundary codes from response boundaries + const responseBoundaryCodes = responseBoundaries.map(boundary => boundary.code.trim()); + + // Finds missing codes from unique boundaries + const missingCodes = uniqueBoundaries.filter(code => !responseBoundaryCodes.includes(code)); + + // Throws error if missing codes exist + if (missingCodes.length > 0) { + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `Boundary codes ${missingCodes.join(', ')} do not exist in hierarchyType ${request?.body?.ResourceDetails?.hierarchyType}` + ); + } +} + +// Validates unique boundaries against the response boundaries. +async function validateUniqueBoundaries(uniqueBoundaries: any[], request: any) { + // Fetches response boundaries in chunks + const responseBoundaries = await fetchBoundariesInChunks(request); + + // Compares unique boundaries with response boundaries + compareBoundariesWithUnique(uniqueBoundaries, responseBoundaries, request); +} + + + + +async function validateBoundaryData(data: any[], request: any, boundaryColumn: any, localizationMap: any) { + const boundarySet = new Set(); // Create a Set to store unique boundaries + logger.info("validating for the boundary data") + const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; + const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap) : null; + if (activeColumnName && uniqueIdentifierColumnName) { + data = data.filter((item: any) => item[activeColumnName] === "Active" || !item[uniqueIdentifierColumnName]); + data.forEach((item: any) => item[activeColumnName] = "Active"); + } + if (data.length == 0) { + if (request?.body?.ResourceDetails?.type == "facility") { + throwError("COMMON", 400, "VALIDATION_ERROR", "All facilities are set to Inactive for this campaign. Please set at least one facility to Active for this campaign or add a new facility for this campaign"); + } + else { + throwError("COMMON", 400, "VALIDATION_ERROR", "Data is empty for this campaign, add atleast one data row"); + } + } + data.forEach((element) => { + const boundaries = element[boundaryColumn]; + if (!boundaries) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Code is required for element in rowNumber ${element['!row#number!']}`); + } + + const boundaryList = boundaries.split(",").map((boundary: any) => boundary.trim()); + if (boundaryList.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `At least 1 boundary is required for element in rowNumber ${element['!row#number!']}`); + } + + for (const boundary of boundaryList) { + if (!boundary) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary format is invalid in rowNumber ${element['!row#number!']}. Put it with one comma between boundary codes`); + } + boundarySet.add(boundary); // Add boundary to the set + } + }); + const uniqueBoundaries = Array.from(boundarySet); + await validateUniqueBoundaries(uniqueBoundaries, request); +} + +// async function validateTargetBoundaryData(data: any[], request: any, boundaryColumn: any, errors: any[], localizationMap?: any) { +// // const responseBoundaries = await fetchBoundariesInChunks(request); +// const responseBoundaries = await getTargetBoundariesRelatedToCampaignId(request, localizationMap); +// const responseBoundaryCodes = responseBoundaries.map((boundary: any) => boundary.code); +// // Iterate through each array of objects +// for (const key in data) { +// const isNotBoundaryOrReadMeTab = key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap); +// if (isNotBoundaryOrReadMeTab) { +// if (Array.isArray(data[key])) { +// const boundaryData = data[key]; +// const boundarySet = new Set(); // Create a Set to store unique boundaries for given sheet +// boundaryData.forEach((element: any, index: number) => { +// const boundaries = element?.[boundaryColumn]; // Access "Boundary Code" property directly +// if (!boundaries) { +// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Boundary Code is required for element at row ${element["!row#number!"]} for sheet ${key}`, sheetName: key }) +// } else { +// if (typeof boundaries !== 'string') { +// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Boundary Code is not of type string at row ${element["!row#number!"]} in boundary sheet ${key}`, sheetName: key }); +// } else { +// const boundaryList = boundaries.split(",").map((boundary: any) => boundary.trim()); +// if (boundaryList.length === 0 || boundaryList.includes('')) { +// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `No boundary code found for row ${element["!row#number!"]} in boundary sheet ${key}`, sheetName: key }) +// } +// if (boundaryList.length > 1) { +// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `More than one Boundary Code found at row ${element["!row#number!"]} of sheet ${key}`, sheetName: key }) +// } +// if (boundaryList.length === 1) { +// const boundaryCode = boundaryList[0]; +// if (boundarySet.has(boundaryCode)) { +// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Duplicacy of boundary Code at row ${element["!row#number!"]} of sheet ${key}`, sheetName: key }) +// } +// if (!responseBoundaryCodes.includes(boundaryCode)) { +// errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Boundary Code at row ${element["!row#number!"]} of sheet ${key} is not present in the selected boundaries`, sheetName: key }) +// } +// boundarySet.add(boundaryCode); +// } +// } +// } +// }); +// } +// } +// } +// } + + + +// async function validateTargetsAtLowestLevelPresentOrNot(data: any[], request: any, errors: any[], localizationMap?: any) { +// const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); +// const modifiedHierarchy = hierarchy.map(ele => `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase()) +// const localizedHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); +// const dataToBeValidated = modifyTargetData(data); +// let maxKeyIndex = -1; +// dataToBeValidated.forEach(obj => { +// const keyIndex = calculateKeyIndex(obj, localizedHierarchy, localizationMap); +// if (keyIndex > maxKeyIndex) { +// maxKeyIndex = keyIndex; +// } +// }) +// const lowestLevelHierarchy = localizedHierarchy[maxKeyIndex]; +// await validateTargets(request, data, lowestLevelHierarchy, errors, localizationMap); +// } + + +async function validateTargets(request: any, data: any[], errors: any[], localizationMap?: any) { + const mdmsResponse = await getMdmsDataBasedOnCampaignType(request); + const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + const requiredColumns = mdmsResponse?.required; + const columnsToValidate = columnsNotToBeFreezed.filter((element: any) => requiredColumns.includes(element)); + const localizedTargetColumnNames = getLocalizedHeaders(columnsToValidate, localizationMap); for (const key in data) { - if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config.values?.readMeTab, localizationMap)) { + if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { if (Array.isArray(data[key])) { const boundaryData = data[key]; boundaryData.forEach((obj: any, index: number) => { @@ -132,34 +265,8 @@ function validateTargetForNormalCampaigns(data: any, errors: any, localizedTarge } } - -async function validateTargets(request: any, data: any[], errors: any[], localizationMap?: any) { - let columnsToValidate: any; - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; - if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0) { - - const modifiedUniqueDeliveryConditions = modifyDeliveryConditions(campaignObject.deliveryRules); - columnsToValidate = generateTargetColumnsBasedOnDeliveryConditions(modifiedUniqueDeliveryConditions, localizationMap); - - } - else { - const mdmsResponse = await getMdmsDataBasedOnCampaignType(request); - const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; - const requiredColumns = mdmsResponse?.required; - columnsToValidate = columnsNotToBeFreezed.filter((element: any) => requiredColumns.includes(element)); - } - const localizedTargetColumnNames = getLocalizedHeaders(columnsToValidate, localizationMap); - if (request?.body?.ResourceDetails?.additionalDetails?.source === "microplan") { - validateTargetsForMicroplanCampaigns(data, errors, localizedTargetColumnNames, localizationMap); - validateLatLongForMicroplanCampaigns(data, errors, localizationMap); - } - else { - validateTargetForNormalCampaigns(data, errors, localizedTargetColumnNames, localizationMap); - } -} - -function validateUnique(schema: any, data: any[], request: any, localizationMap: any) { +async function validateUnique(schema: any, data: any[], request: any) { + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); if (schema?.unique) { const uniqueElements = schema.unique; const errors = []; @@ -170,7 +277,7 @@ function validateUnique(schema: any, data: any[], request: any, localizationMap: // Iterate over each data object and check uniqueness for (const item of data) { const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName; - const localizedUniqueIdentifierColumnName = getLocalizedName(uniqueIdentifierColumnName, localizationMap); + const localizedUniqueIdentifierColumnName = await getLocalizedName(uniqueIdentifierColumnName, localizationMap); const value = item[element]; const rowNum = item['!row#number!']; if (!localizedUniqueIdentifierColumnName || !item[localizedUniqueIdentifierColumnName]) { @@ -225,7 +332,6 @@ function validatePhoneNumber(datas: any[], localizationMap: any) { } } - async function changeSchemaErrorMessage(schema: any, localizationMap?: any) { if (schema?.errorMessage) { for (const key in schema.errorMessage) { @@ -237,54 +343,9 @@ async function changeSchemaErrorMessage(schema: any, localizationMap?: any) { return schema; // Return unmodified schema if no error message } -function validateData(data: any[], validationErrors: any[], activeColumnName: any, uniqueIdentifierColumnName: any, validate: any) { - data.forEach((item: any) => { - if (activeColumnName) { - if (!item?.[activeColumnName]) { - validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should not be empty` }] }); - } - else if (item?.[activeColumnName] != "Active" && item?.[activeColumnName] != "Inactive") { - validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should be equal to one of the allowed values. Allowed values are Active, Inactive` }] }); - } - } - const active = activeColumnName ? item[activeColumnName] : "Active"; - if (active == "Active" || !item?.[uniqueIdentifierColumnName]) { - const validationResult = validate(item); - if (!validationResult) { - validationErrors.push({ index: item?.["!row#number!"], errors: validate.errors }); - } - } - }); -} - -function enrichRowMappingViaValidation(validationErrors: any[], rowMapping: any, localizationMap?: any) { - if (validationErrors.length > 0) { - const errorMessage = validationErrors.map(({ index, message, errors }) => { - const formattedErrors = errors ? errors.map((error: any) => { - let instancePath = error.instancePath || ''; // Assign an empty string if dataPath is not available - if (instancePath.startsWith('/')) { - instancePath = instancePath.slice(1); - } - if (error.keyword === 'required') { - const missingProperty = error.params?.missingProperty || ''; - return `Data at row ${index} in column '${missingProperty}' should not be empty`; - } - let formattedError = `in column '${instancePath}' ${getLocalizedName(error.message, localizationMap)}`; - if (error.keyword === 'enum' && error.params && error.params.allowedValues) { - formattedError += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; - } - return `Data at row ${index} ${formattedError}` - }).join(' ; ') : message; - return formattedErrors; - }).join(' ; '); - throwError("COMMON", 400, "VALIDATION_ERROR", errorMessage); - } else { - logger.info("All Data rows are valid."); - } -} -export async function validateViaSchema(data: any, schema: any, request: any, localizationMap?: any) { +async function validateViaSchema(data: any, schema: any, request: any, localizationMap?: any) { if (schema) { const newSchema: any = await changeSchemaErrorMessage(schema, localizationMap) const ajv = new Ajv({ allErrors: true, strict: false }); // enable allErrors to get all validation errors @@ -296,124 +357,70 @@ export async function validateViaSchema(data: any, schema: any, request: any, lo if (request?.body?.ResourceDetails?.type == "user") { validatePhoneNumber(data, localizationMap); } - if (data?.length > 0 && request?.body?.ResourceDetails?.additionalDetails?.source != "microplan") { - if (!request?.body?.parentCampaignObject && data[0]?.[getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", localizationMap)]) { - throwError("COMMON", 400, "VALIDATION_ERROR", `${request?.body?.ResourceDetails?.type} template downloaded from update campaign flow has been uploaded in create campaign flow`); - } - validateData(data, validationErrors, activeColumnName, uniqueIdentifierColumnName, validate); - validateUnique(newSchema, data, request, localizationMap); - enrichRowMappingViaValidation(validationErrors, request?.body?.rowMapping, localizationMap); - } - if (data?.length == 0) { - throwError("FILE", 400, "INVALID_FILE_ERROR", "Data rows cannot be empty"); - } - } else { - logger.info("Skipping schema validation"); - } -} - -function validateDataSheetWise(data: any, validate: any, validationErrors: any[], uniqueIdentifierColumnName: any, activeColumnName: any) { - data.forEach((item: any) => { - const validationResult = validate(item); - if (!validationResult) { - validationErrors.push({ index: item?.["!row#number!"], errors: validate.errors }); - } - }); -} - -function enrichRowMappingViaValidationSheetwise(rowMapping: any, validationErrors: any[], localizationMap: any) { - if (validationErrors.length > 0) { - validationErrors.map(({ index, message, errors }) => { - if (errors) { - errors.map((error: any) => { - let instancePath = error.instancePath || ''; // Assign an empty string if instancePath is not available - if (instancePath.startsWith('/')) { - instancePath = instancePath.slice(1); + if (data?.length > 0) { + data.forEach((item: any) => { + if (activeColumnName) { + if (!item?.[activeColumnName]) { + validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should not be empty` }] }); } - - // Handle 'required' keyword errors - if (error.keyword === 'required') { - const missingProperty = error.params?.missingProperty || ''; - if (!rowMapping[index]) { - rowMapping[index] = []; - } - rowMapping[index].push(`Data in column '${missingProperty}' should not be empty`); + else if (item?.[activeColumnName] != "Active" && item?.[activeColumnName] != "Inactive") { + validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should be equal to one of the allowed values. Allowed values are Active, Inactive` }] }); } - else { - // Format the general error message - let formattedError = `Data in column '${instancePath}' ${getLocalizedName(error.message, localizationMap)}`; - - // Handle 'enum' keyword errors - if (error.keyword === 'enum' && error.params && error.params.allowedValues) { - formattedError += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; + } + const active = activeColumnName ? item[activeColumnName] : "Active"; + if (active == "Active" || !item?.[uniqueIdentifierColumnName]) { + const validationResult = validate(item); + if (!validationResult) { + validationErrors.push({ index: item?.["!row#number!"], errors: validate.errors }); + } + } + }); + await validateUnique(newSchema, data, request); + if (validationErrors.length > 0) { + const errorMessage = validationErrors.map(({ index, message, errors }) => { + const formattedErrors = errors ? errors.map((error: any) => { + let instancePath = error.instancePath || ''; // Assign an empty string if dataPath is not available + if (instancePath.startsWith('/')) { + instancePath = instancePath.slice(1); } - else if (error.keyword === 'pattern') { - formattedError = `Data in column '${instancePath}' is invalid` + if (error.keyword === 'required') { + const missingProperty = error.params?.missingProperty || ''; + return `Data at row ${index} in column '${missingProperty}' should not be empty`; } - - // Ensure rowMapping[index] exists - if (!rowMapping[index]) { - rowMapping[index] = []; + let formattedError = `in column '${instancePath}' ${getLocalizedName(error.message, localizationMap)}`; + if (error.keyword === 'enum' && error.params && error.params.allowedValues) { + formattedError += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; } - rowMapping[index].push(`${formattedError}`); - } - }) - } - }); - } - else { - logger.info("All Data rows are valid."); - } -} - -export async function validateViaSchemaSheetWise(dataFromExcel: any, schema: any, request: any, localizationMap?: any) { - const errorMap: any = {}; - for (const sheetName of Object.keys(dataFromExcel)) { - const data = dataFromExcel[sheetName]; - const rowMapping: any = {}; - if (schema) { - const newSchema: any = await changeSchemaErrorMessage(schema, localizationMap) - const ajv = new Ajv({ allErrors: true, strict: false }); // enable allErrors to get all validation errors - addAjvErrors(ajv); - const validate = ajv.compile(newSchema); - const validationErrors: any[] = []; - const uniqueIdentifierColumnName = getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap); - const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; - if (request?.body?.ResourceDetails?.type == "user" && request?.body?.ResourceDetails?.additionalDetails?.source == "microplan") { - validateUserForMicroplan(data, sheetName, request, errorMap, newSchema, rowMapping, localizationMap); - } - else { - if (request?.body?.ResourceDetails?.type == "user") { - validatePhoneNumberSheetWise(data, localizationMap, rowMapping); - } - if (data?.length > 0) { - validateDataSheetWise(data, validate, validationErrors, uniqueIdentifierColumnName, activeColumnName); - validateUniqueSheetWise(newSchema, data, request, rowMapping, localizationMap); - enrichRowMappingViaValidationSheetwise(rowMapping, validationErrors, localizationMap); - } else { - errorMap[sheetName] = { 2: ["Data rows cannot be empty"] }; - } + return `Data at row ${index} ${formattedError}` + }).join(' ; ') : message; + return formattedErrors; + }).join(' ; '); + throwError("COMMON", 400, "VALIDATION_ERROR", errorMessage); + } else { + logger.info("All Data rows are valid."); } } else { - logger.info("Skipping schema validation"); - } - if (Object.keys(rowMapping).length > 0) { - errorMap[sheetName] = rowMapping; + throwError("FILE", 400, "INVALID_FILE_ERROR", "Data rows cannot be empty"); } + } else { + logger.info("Skipping schema validation"); } - return errorMap; } async function validateSheetData(data: any, request: any, schema: any, boundaryValidation: any, localizationMap?: { [key: string]: string }) { await validateViaSchema(data, schema, request, localizationMap); + if (boundaryValidation) { + const localisedBoundaryCode = getLocalizedName(boundaryValidation?.column, localizationMap) + await validateBoundaryData(data, request, localisedBoundaryCode, localizationMap); + } } -async function validateTargetSheetData(data: any, request: any, boundaryValidation: any, differentTabsBasedOnLevel: any, localizationMap?: any) { +async function validateTargetSheetData(data: any, request: any, boundaryValidation: any, localizationMap?: any) { try { const errors: any[] = []; - await validateHeadersOfTargetSheet(request, differentTabsBasedOnLevel, localizationMap); + await validateHeadersOfTargetSheet(request, localizationMap); if (boundaryValidation) { // const localizedBoundaryValidationColumn = getLocalizedName(boundaryValidation?.column, localizationMap) // await validateTargetBoundaryData(data, request, localizedBoundaryValidationColumn, errors, localizationMap); @@ -433,11 +440,11 @@ async function validateTargetSheetData(data: any, request: any, boundaryValidati } -async function validateHeadersOfTargetSheet(request: any, differentTabsBasedOnLevel: any, localizationMap?: any) { +async function validateHeadersOfTargetSheet(request: any, localizationMap?: any) { const fileUrl = await validateFile(request); const targetWorkbook: any = await getTargetWorkbook(fileUrl); const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); - const finalValidHeadersForTargetSheetAsPerCampaignType = await getFinalValidHeadersForTargetSheetAsPerCampaignType(request, hierarchy, differentTabsBasedOnLevel, localizationMap); + const finalValidHeadersForTargetSheetAsPerCampaignType = await getFinalValidHeadersForTargetSheetAsPerCampaignType(request, hierarchy, localizationMap); logger.info("finalValidHeadersForTargetSheetAsPerCampaignType :" + JSON.stringify(finalValidHeadersForTargetSheetAsPerCampaignType)); logger.info("validating headers of target sheet started") validateHeadersOfTabsWithTargetInTargetSheet(targetWorkbook, finalValidHeadersForTargetSheetAsPerCampaignType); @@ -481,7 +488,7 @@ function validateStorageCapacity(obj: any, index: any) { async function validateCampaignId(request: any) { - const { campaignId, tenantId, type, additionalDetails } = request?.body?.ResourceDetails; + const { campaignId, tenantId, type } = request?.body?.ResourceDetails; if (type == "boundary") { return; } @@ -489,30 +496,28 @@ async function validateCampaignId(request: any) { throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignId is missing"); } else { - // const searchBody = { - const CampaignDetails= { + const searchBody = { + CampaignDetails: { ids: [campaignId], tenantId: tenantId } - // const req: any = replicateRequest(request, searchBody); - const response = await searchProjectTypeCampaignService(CampaignDetails); + } + const req: any = replicateRequest(request, searchBody); + const response = await searchProjectTypeCampaignService(req); if (response?.CampaignDetails?.[0]) { - const boundaries = await getBoundariesFromCampaignSearchResponse(request, response?.CampaignDetails?.[0]); - if (!boundaries) { + const campaign = response?.CampaignDetails?.[0] + if (!campaign?.boundaries) { throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign with given campaignId does not have any boundaries"); } - if (!Array.isArray(boundaries)) { + if (!Array.isArray(campaign?.boundaries)) { throwError("COMMON", 400, "VALIDATION_ERROR", "Boundaries of campaign with given campaignId is not an array"); } - if (boundaries?.length === 0) { + if (campaign?.boundaries?.length === 0) { throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign with given campaignId does not have any boundaries"); } - request.body.campaignBoundaries = boundaries } else { - if (!(additionalDetails?.source == "microplan" && type == "user")) { - throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while validating campaignId"); - } + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while validating campaignId"); } } } @@ -523,12 +528,9 @@ async function validateCreateRequest(request: any, localizationMap?: any) { throwError("COMMON", 400, "VALIDATION_ERROR", "ResourceDetails is missing or empty or null"); } else { - const type = request?.body?.ResourceDetails?.type; // validate create request body validateBodyViaSchema(createRequestSchema, request.body.ResourceDetails); - if (type !== "boundaryManagement" && request?.body?.ResourceDetails.campaignId !== "default") { - await validateCampaignId(request); - } + await validateCampaignId(request); await validateHierarchyType(request, request?.body?.ResourceDetails?.hierarchyType, request?.body?.ResourceDetails?.tenantId); if (request?.body?.ResourceDetails?.tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is not matching with userInfo"); @@ -538,6 +540,13 @@ async function validateCreateRequest(request: any, localizationMap?: any) { if (request.body.ResourceDetails.type == 'boundary') { await validateBoundarySheetData(request, fileUrl, localizationMap); } + // if (request?.body?.ResourceDetails?.type == 'boundaryWithTarget') { + // const targetWorkbook: any = await getTargetWorkbook(fileUrl); + // const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); + // const finalValidHeadersForTargetSheetAsPerCampaignType = await getFinalValidHeadersForTargetSheetAsPerCampaignType(request, hierarchy, localizationMap); + // logger.info("finalValidHeadersForTargetSheetAsPerCampaignType :" + JSON.stringify(finalValidHeadersForTargetSheetAsPerCampaignType)); + // validateTabsWithTargetInTargetSheet(targetWorkbook, finalValidHeadersForTargetSheetAsPerCampaignType); + // } } } @@ -545,10 +554,9 @@ function validateHeadersOfTabsWithTargetInTargetSheet(targetWorkbook: any, expec targetWorkbook.eachSheet((worksheet: any, sheetId: any) => { if (sheetId > 2) { // Starting from the second sheet // Convert the sheet to an array of headers - let headersToValidate = worksheet.getRow(1).values + const headersToValidate = worksheet.getRow(1).values .filter((header: any) => header !== undefined && header !== null && header.toString().trim() !== '') .map((header: any) => header.toString().trim()); - headersToValidate = headersToValidate.filter((header: string) => header !== '#status#' && header !== '#errorDetails#'); if (!_.isEqual(expectedHeadersForTargetSheet, headersToValidate)) { throwError("COMMON", 400, "VALIDATION_ERROR", `Headers not according to the template in Target sheet ${worksheet.name}`); } @@ -660,7 +668,6 @@ async function validateCampaignBoundary(boundaries: any[], hierarchyType: any, t } } - async function validateProjectCampaignBoundaries(boundaries: any[], hierarchyType: any, tenantId: any, request: any): Promise { if (!request?.body?.CampaignDetails?.projectId) { if (boundaries) { @@ -698,18 +705,14 @@ async function validateBoundariesForTabs(CampaignDetails: any, resource: any, re // Fetch file response const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId, fileStoreIds: resource.fileStoreId }, "get"); const datas = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, localizedTab, true, undefined, localizationMap); - var boundaryColumn: any; - if (resource?.additionalDetails?.source == 'microplan') { - boundaryColumn = getLocalizedName(createAndSearch?.[`${resource.type}Microplan`]?.boundaryValidation?.column, localizationMap); - } - else { - boundaryColumn = getLocalizedName(createAndSearch?.[resource.type]?.boundaryValidation?.column, localizationMap); - } + + const boundaryColumn = getLocalizedName(createAndSearch?.[resource.type]?.boundaryValidation?.column, localizationMap); + // Initialize resource boundary codes as a set for uniqueness const resourceBoundaryCodesArray: any[] = []; var activeColumnName: any = null; if (createAndSearch?.[resource.type]?.activeColumn && createAndSearch?.[resource.type]?.activeColumnName) { - activeColumnName = getLocalizedName(createAndSearch?.[resource.type]?.activeColumnName, localizationMap); + activeColumnName = getLocalizedName(createAndSearch?.[resource.type]?.activeColumn, localizationMap); } datas.forEach((data: any) => { const codes = data?.[boundaryColumn]?.split(',').map((code: string) => code.trim()) || []; @@ -727,9 +730,8 @@ async function validateBoundariesForTabs(CampaignDetails: any, resource: any, re var missingBoundaries = rowData.boundaryCodes.filter((code: any) => !boundaryCodesArray.includes(code)); if (missingBoundaries.length > 0) { const errorString = `The following boundary codes are not present in selected boundaries : ${missingBoundaries.join(', ')}` - errors.push({ status: "BOUNDARYERROR", rowNumber: rowData.rowNumber, errorDetails: errorString }) + errors.push({ status: "BOUNDARYMISSING", rowNumber: rowData.rowNumber, errorDetails: errorString }) } - validateFacilityBoundaryForLowestLevel(request, boundaries, rowData, errors, localizationMap); } if (errors?.length > 0) { request.body.ResourceDetails.status = resourceDataStatuses.invalid @@ -808,16 +810,14 @@ async function validateProjectCampaignResources(resources: any, request: any) { missingTypes.push(type); } } - if ((!request?.body?.parentCampaign) || (request?.body?.parentCampaign && request?.body?.CampaignDetails?.boundaries && request.body.CampaignDetails.boundaries.length > 0)) { - if (missingTypes.length > 0) { - const missingTypesMessage = `Missing resources of types: ${missingTypes.join(', ')}`; - throwError("COMMON", 400, "VALIDATION_ERROR", missingTypesMessage); - } + + if (missingTypes.length > 0) { + const missingTypesMessage = `Missing resources of types: ${missingTypes.join(', ')}`; + throwError("COMMON", 400, "VALIDATION_ERROR", missingTypesMessage); } if (request?.body?.CampaignDetails?.action === "create" && request?.body?.CampaignDetails?.resources) { - logger.info(`skipResourceCheckValidationBeforeCreateForLocalTesting flag is ${config.values.skipResourceCheckValidationBeforeCreateForLocalTesting }`); - !config.values.skipResourceCheckValidationBeforeCreateForLocalTesting && await validateResources(request.body.CampaignDetails.resources, request); + await validateResources(request.body.CampaignDetails.resources, request); } } @@ -826,46 +826,33 @@ async function validateProjectCampaignResources(resources: any, request: any) { function validateProjectCampaignMissingFields(CampaignDetails: any) { validateCampaignBodyViaSchema(campaignDetailsSchema, CampaignDetails) + const { startDate, endDate } = CampaignDetails; + if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate"); + } + const today: any = Date.now(); + if (startDate <= today) { + throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); + } } function validateDraftProjectCampaignMissingFields(CampaignDetails: any) { validateCampaignBodyViaSchema(campaignDetailsDraftSchema, CampaignDetails) -} - -async function validateParent(request: any, actionInUrl: any) { - if (request?.body?.CampaignDetails?.parentId) { - const tenantId = request.body.CampaignDetails?.tenantId - const CampaignDetails = { - tenantId: tenantId, - ids: [request.body.CampaignDetails?.parentId] + const { startDate, endDate, action } = CampaignDetails; + if (action != "changeDates") { + if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate"); } - const parentSearchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) - if (Array.isArray(parentSearchResponse?.CampaignDetails)) { - if (actionInUrl == "create") { - if (parentSearchResponse?.CampaignDetails?.length > 0 && parentSearchResponse?.CampaignDetails?.[0]?.status == "created" && - parentSearchResponse?.CampaignDetails?.[0]?.isActive) { - request.body.parentCampaign = parentSearchResponse?.CampaignDetails[0] - } - else { - throwError("CAMPAIGN", 400, "PARENT_CAMPAIGN_ERROR", "Parent Campaign can't be inactive when creating child campaign"); - } - } - else { - if (parentSearchResponse?.CampaignDetails?.length > 0 && parentSearchResponse?.CampaignDetails?.[0]?.status == "created" && - !parentSearchResponse?.CampaignDetails?.[0]?.isActive) { - request.body.parentCampaign = parentSearchResponse?.CampaignDetails[0] - } - else { - throwError("CAMPAIGN", 400, "PARENT_CAMPAIGN_ERROR", "Parent Campaign can't be active when updating child campaign"); - } - - } + const today: any = Date.now(); + if (startDate <= today) { + throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); } } } async function validateCampaignName(request: any, actionInUrl: any) { - const { campaignName, tenantId } = request.body.CampaignDetails; + const CampaignDetails = request.body.CampaignDetails; + const { campaignName, tenantId } = CampaignDetails; if (!campaignName) { throwError("COMMON", 400, "VALIDATION_ERROR", "campaignName is required"); } @@ -873,38 +860,25 @@ async function validateCampaignName(request: any, actionInUrl: any) { throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); } if (campaignName.length >= 2) { - // const searchBody = { - // RequestInfo: request.body.RequestInfo, - const CampaignDetails = { + const searchBody = { + RequestInfo: request.body.RequestInfo, + CampaignDetails: { tenantId: tenantId, - campaignName: campaignName, - status: [campaignStatuses.drafted, campaignStatuses.started, campaignStatuses.inprogress], - } - // } - if (request.body?.parentCampaign) { - if (request?.body?.CampaignDetails?.campaignName != request?.body?.parentCampaign?.campaignName) { - throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_NOT_MATCHING_PARENT_ERROR", "Campaign name should be same as that of parent"); + campaignName: campaignName } } - // const req: any = replicateRequest(request, searchBody) - const searchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) + const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(req) if (Array.isArray(searchResponse?.CampaignDetails)) { if (searchResponse?.CampaignDetails?.length > 0) { const allCampaigns = searchResponse?.CampaignDetails; logger.info(`campaignName to match : ${"'"}${campaignName}${"'"}`) - const matchingCampaigns: any[] = allCampaigns.filter((campaign: any) => campaign?.campaignName === campaignName); - for (const campaignWithMatchingName of matchingCampaigns) { - if (campaignWithMatchingName && actionInUrl == "create") { - if (!request.body.CampaignDetails?.parentId) { - throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); - } - else if (campaignWithMatchingName?.id != request.body.CampaignDetails?.parentId) { - throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); - } - } - else if (campaignWithMatchingName && actionInUrl == "update" && campaignWithMatchingName?.id != request.body.CampaignDetails?.id) { - throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); - } + const campaignWithMatchingName: any = allCampaigns.find((campaign: any) => "'" + campaign?.campaignName + "'" == "'" + campaignName + "'") || null; + if (campaignWithMatchingName && actionInUrl == "create") { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } + else if (campaignWithMatchingName && actionInUrl == "update" && campaignWithMatchingName?.id != CampaignDetails?.id) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); } } } @@ -919,15 +893,15 @@ async function validateById(request: any) { if (!id) { throwError("COMMON", 400, "VALIDATION_ERROR", "id is required"); } - // const searchBody = { - // RequestInfo: request.body.RequestInfo, - const CampaignDetails ={ + const searchBody = { + RequestInfo: request.body.RequestInfo, + CampaignDetails: { tenantId: tenantId, ids: [id] } - // } - // const req: any = replicateRequest(request, searchBody) - const searchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) + } + const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(req) if (Array.isArray(searchResponse?.CampaignDetails)) { if (searchResponse?.CampaignDetails?.length > 0) { logger.debug(`CampaignDetails : ${getFormattedStringForDebug(searchResponse?.CampaignDetails)}`); @@ -970,7 +944,7 @@ async function validateProjectType(request: any, projectType: any, tenantId: any } } const params = { tenantId: tenantId } - const searchResponse: any = await httpRequest(config.host.mdmsV2 + config?.paths?.mdms_v1_search, searchBody, params); + const searchResponse: any = await httpRequest(config.host.mdms + "egov-mdms-service/v1/_search", searchBody, params); if (searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes && Array.isArray(searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes)) { const projectTypes = searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; if (!projectTypes.includes(projectType)) { @@ -1020,49 +994,29 @@ async function validateChangeDatesRequest(request: any) { } async function validateCampaignBody(request: any, CampaignDetails: any, actionInUrl: any) { - const { hierarchyType, action, tenantId, resources, projectType } = CampaignDetails; + const { hierarchyType, action, tenantId, boundaries, resources, projectType } = CampaignDetails; if (action == "changeDates") { await validateChangeDatesRequest(request); } else if (action == "create") { validateProjectCampaignMissingFields(CampaignDetails); - await validateParent(request, actionInUrl) - validateBoundariesIfParentPresent(request); - validateProjectDatesForCampaign(request, CampaignDetails); await validateCampaignName(request, actionInUrl); if (tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is not matching with userInfo"); } await validateHierarchyType(request, hierarchyType, tenantId); await validateProjectType(request, projectType, tenantId); - await validateProjectCampaignBoundaries(request?.body?.boundariesCombined, hierarchyType, tenantId, request); + await validateProjectCampaignBoundaries(boundaries, hierarchyType, tenantId, request); await validateProjectCampaignResources(resources, request); - await validateProductVariant(request); } else { validateDraftProjectCampaignMissingFields(CampaignDetails); - await validateParent(request, actionInUrl); - validateBoundariesIfParentPresent(request); - validateProjectDatesForCampaign(request, CampaignDetails); await validateCampaignName(request, actionInUrl); await validateHierarchyType(request, hierarchyType, tenantId); await validateProjectType(request, projectType, tenantId); } } -function validateProjectDatesForCampaign(request: any, CampaignDetails: any) { - if (!request?.body?.parentCampaign) { - const { startDate, endDate } = CampaignDetails; - if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) { - throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate"); - } - const today: any = Date.now(); - if (startDate <= today) { - throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); - } - } -} - async function validateProjectCampaignRequest(request: any, actionInUrl: any) { const CampaignDetails = request.body.CampaignDetails; const { id, action } = CampaignDetails; @@ -1077,20 +1031,11 @@ async function validateProjectCampaignRequest(request: any, actionInUrl: any) { if (!action) { throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails.action is required and must be either 'create' or 'draft'") } - if (!(action == "create" || action == "draft" || action == "changeDates" || action == "retry")) { - throwError("COMMON", 400, "VALIDATION_ERROR", "action can only be create, draft, retry or changeDates"); - } - if (actionInUrl == "retry") { - await validateForRetry(request); + if (!(action == "create" || action == "draft" || action == "changeDates")) { + throwError("COMMON", 400, "VALIDATION_ERROR", "action can only be create, draft or changeDates"); } if (actionInUrl == "update") { await validateById(request); - await validateIsActive(request); - } - if (actionInUrl == "create") { - if (!request?.body?.CampaignDetails?.isActive) { - request.body.CampaignDetails.isActive = true; - } } if (action == "changeDates" && actionInUrl == "create") { throwError("COMMON", 400, "VALIDATION_ERROR", "changeDates is not allowed during create"); @@ -1098,109 +1043,6 @@ async function validateProjectCampaignRequest(request: any, actionInUrl: any) { await validateCampaignBody(request, CampaignDetails, actionInUrl); } -async function validateForRetry(request: any) { - if (!request.body || !request.body.CampaignDetails) { - throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails are missing in the request body"); - } - const { id, tenantId } = request.body.CampaignDetails; - if (!id) { - throwError("COMMON", 400, "VALIDATION_ERROR", "id is required"); - } - if (!tenantId) { - throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); - } - // const searchBody = { - // RequestInfo: request.body.RequestInfo, - const CampaignDetails= { - tenantId: tenantId, - ids: [id] - } - // } - // const req: any = replicateRequest(request, searchBody) - const searchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) - if (Array.isArray(searchResponse?.CampaignDetails)) { - if (searchResponse?.CampaignDetails?.length > 0) { - logger.debug(`CampaignDetails : ${getFormattedStringForDebug(searchResponse?.CampaignDetails)}`); - request.body.ExistingCampaignDetails = searchResponse?.CampaignDetails[0]; - if (request.body.ExistingCampaignDetails?.status != campaignStatuses?.failed) { - throwError("COMMON", 400, "VALIDATION_ERROR", `Campaign can only be retried in failed state.`); - } - request.body.CampaignDetails.status = campaignStatuses?.drafted; - var updatedInnerCampaignDetails = {} - enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) - request.body.CampaignDetails.campaignDetails = updatedInnerCampaignDetails; - const producerMessage: any = { - CampaignDetails: request?.body?.CampaignDetails - } - await produceModifiedMessages(producerMessage, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC); - - if (!request.body.CampaignDetails.additionalDetails.retryCycle) { - // If not present, initialize it as an empty array - request.body.CampaignDetails.additionalDetails.retryCycle = []; - } - - // Step 2: Push new data to the `retryCycle` array - request.body.CampaignDetails.additionalDetails.retryCycle.push({ - error: request.body.CampaignDetails.additionalDetails.error, - retriedAt: Date.now(), - failedAt: request.body.CampaignDetails.auditDetails.lastModifiedTime - }); - } - else { - throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND"); - } - } - else { - throwError("CAMPAIGN", 500, "CAMPAIGN_SEARCH_ERROR"); - } -} - -async function validateProductVariant(request: any) { - const deliveryRules = request?.body?.CampaignDetails?.deliveryRules; - - if (!Array.isArray(deliveryRules)) { - throwError("COMMON", 400, "VALIDATION_ERROR", "deliveryRules must be an array"); - } - - deliveryRules.forEach((rule: any, index: number) => { - const productVariants = rule?.resources; - if (!Array.isArray(productVariants) || productVariants.length === 0) { - throwError("COMMON", 400, "VALIDATION_ERROR", `deliveryRules[${index}].resources must be a non-empty array`); - } - }); - const pvarIds= getPvarIds(request?.body); - await validatePvarIds(pvarIds as string[]); - logger.info("Validated product variants successfully"); -} - -async function validatePvarIds(pvarIds: string[]) { - // Validate that pvarIds is not null, undefined, or empty, and that no element is null or undefined - if (!pvarIds?.length || pvarIds.some((id:any) => !id)) { - throwError("COMMON", 400, "VALIDATION_ERROR", "productVariantId is required in every delivery rule's resources"); - } - - // Fetch product variants using the fetchProductVariants function - const allProductVariants = await fetchProductVariants(pvarIds); - - // Extract the ids of the fetched product variants - const fetchedIds = new Set(allProductVariants.map((pvar: any) => pvar?.id)); - - // Identify missing or invalid product variants - const missingPvarIds = pvarIds.filter((id: any) => !fetchedIds.has(id)); - - if (missingPvarIds.length) { - throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid product variant ${missingPvarIds.length === 1 ? 'id' : 'ids'}: ${missingPvarIds.join(", ")}`); - } -} - - -async function validateIsActive(request: any) { - if (!request?.body?.CampaignDetails.isActive) { - throwError("COMMON", 400, "VALIDATION_ERROR", "Can't update isActive") - } -} - - async function validateSearchProjectCampaignRequest(request: any) { const CampaignDetails = request.body.CampaignDetails; if (!CampaignDetails) { @@ -1317,10 +1159,9 @@ async function validateDownloadRequest(request: any) { await validateHierarchyType(request, hierarchyType, tenantId); } -async function immediateValidationForTargetSheet(request: any, dataFromSheet: any, differentTabsBasedOnLevel: any, localizationMap: any) { +async function immediateValidationForTargetSheet(dataFromSheet: any, localizationMap: any) { logger.info("validating all district tabs present started") - validateAllDistrictTabsPresentOrNot(request, dataFromSheet, differentTabsBasedOnLevel, localizationMap); - await validateExtraBoundariesForMicroplan(request, dataFromSheet, localizationMap); + validateAllDistrictTabsPresentOrNot(dataFromSheet, localizationMap); logger.info("validation of all district tabs present completed") for (const key in dataFromSheet) { if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { @@ -1329,18 +1170,15 @@ async function immediateValidationForTargetSheet(request: any, dataFromSheet: an if (dataArray.length === 0) { throwError("COMMON", 400, "VALIDATION_ERROR", `The Target Sheet ${key} you have uploaded is empty`) } - const root = getLocalizedName(differentTabsBasedOnLevel, localizationMap); + const root = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); for (const boundaryRow of dataArray) { for (const columns in boundaryRow) { if (columns.startsWith('__EMPTY')) { throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid column has some random data in Target Sheet ${key} at row number ${boundaryRow['!row#number!']}`); } - if (!request?.body?.parentCampaignObject && columns.endsWith('(OLD)')) { - throwError("COMMON", 400, "VALIDATION_ERROR", "Target template downloaded from update campaign flow has been uploaded in create campaign flow") - } } if (!boundaryRow[root]) { - throwError("COMMON", 400, "VALIDATION_ERROR", ` ${root} column is empty in Target Sheet ${key} at row number ${boundaryRow['!row#number!']}. Please upload from downloaded template only.`); + throwError("COMMON", 400, "VALIDATION_ERROR", ` ${root} column is empty in Target Sheet ${key} at row number ${boundaryRow['!row#number!']}`); } } } @@ -1349,18 +1187,19 @@ async function immediateValidationForTargetSheet(request: any, dataFromSheet: an } -function validateAllDistrictTabsPresentOrNot(request: any, dataFromSheet: any, differentTabsBasedOnLevel: any, localizationMap?: any) { +function validateAllDistrictTabsPresentOrNot(dataFromSheet: any, localizationMap?: any) { let tabsIndex = 2; logger.info("target sheet getting validated for different districts"); + const differentTabsBasedOnLevel = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); const tabsOfDistrict = getDifferentDistrictTabs(dataFromSheet[getLocalizedName(config?.boundary?.boundaryTab, localizationMap)], differentTabsBasedOnLevel); logger.info("found " + tabsOfDistrict?.length + " districts"); logger.debug("actual districts in boundary data sheet : " + getFormattedStringForDebug(tabsOfDistrict)); const tabsFromTargetSheet = Object.keys(dataFromSheet); logger.info("districts present in user filled sheet : " + (tabsFromTargetSheet?.length - tabsIndex)); - logger.debug("districts present in user filled sheet (exclude first two tabs): " + getFormattedStringForDebug(tabsFromTargetSheet)); + logger.debug("districts present in user filled sheet : " + getFormattedStringForDebug(tabsFromTargetSheet)); if (tabsFromTargetSheet.length - tabsIndex !== tabsOfDistrict.length) { - throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tabs uploaded by user is either less or more than the ${differentTabsBasedOnLevel} in the boundary system. Please upload from downloaded template only.`); + throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tabs uplaoded by user is either less or more than the ${differentTabsBasedOnLevel} in the boundary system `) } else { for (let index = tabsIndex; index < tabsFromTargetSheet.length; index++) { const tab = tabsFromTargetSheet[index]; // Get the current tab @@ -1368,134 +1207,9 @@ function validateAllDistrictTabsPresentOrNot(request: any, dataFromSheet: any, d throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tab ${tab} not present in the Target Sheet Uploaded`); } } - const MissingDistricts: any = []; - const campaignBoundaries = request?.body?.campaignBoundaries; - if (campaignBoundaries && campaignBoundaries?.length > 0) { - const districtsLocalised = campaignBoundaries - .filter((data: any) => getLocalizedName(`${request?.body?.ResourceDetails?.hierarchyType}_${data.type.toUpperCase()}`, localizationMap).toLocaleLowerCase() == differentTabsBasedOnLevel.toLowerCase()) - .map((data: any) => getLocalizedName(data?.code, localizationMap)) || []; - - tabsOfDistrict.forEach((tab: any) => { - if (!districtsLocalised.includes(tab)) { - MissingDistricts.push(tab); - } - }); - } - - if (MissingDistricts.length > 0) { - throwError("COMMON", 400, "VALIDATION_ERROR", `Districts ${MissingDistricts.join(', ')} not present in the Target Sheet Uploaded`); - } - } - -} - -function validateSearchProcessTracksRequest(request: any) { - if (!request?.query?.campaignId) { - throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignId is required in params"); - } -} - -async function validateMicroplanRequest(request: any) { - const { tenantId, campaignId, planConfigurationId } = request.body.MicroplanDetails; - if (!tenantId) { - throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); - } - if (!campaignId) { - throwError("COMMON", 400, "VALIDATION_ERROR", "campignId is required"); - } - if (!planConfigurationId) { - throwError("COMMON", 400, "VALIDATION_ERROR", "planConfigurationId is required"); - } - logger.info("All required fields are present"); - - await validateCampaignFromId(request); - await validatePlanFacility(request); -} - -async function validatePlanFacility(request: any) { - const planConfigSearchResponse = await planConfigSearch(request); - const planFacilitySearchResponse = await planFacilitySearch(request); - - if (planFacilitySearchResponse.PlanFacility.length === 0) { - throwError("COMMAN", 400, "Plan facilities not found"); - } - request.body.PlanFacility = planFacilitySearchResponse.PlanFacility; - request.body.planConfig = planConfigSearchResponse.PlanConfiguration[0]; -} - -async function validateCampaignFromId(request: any) { - const { tenantId, campaignId } = request.body.MicroplanDetails; - - // const searchBody = { - // RequestInfo: request.body.RequestInfo, - const campaignDetails = { - tenantId: tenantId, - ids: [campaignId] - } - // } - - // const req: any = replicateRequest(request, searchBody) - const searchResponse: any = await searchProjectTypeCampaignService(campaignDetails); - - if (searchResponse?.CampaignDetails?.length == 0) { - throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND"); } - logger.info("Campaign Found"); - request.body.CampaignDetails = searchResponse?.CampaignDetails[0]; -} - - -function validateBoundarySheetDataInCreateFlow(boundarySheetData: any, localizedHeadersOfBoundarySheet: any) { - const firstColumnValues = new Set(); - const firstColumn = localizedHeadersOfBoundarySheet[0]; - - boundarySheetData.forEach((obj: any, index: number) => { - let firstEmptyFound = false; - // Collect value from the first column - if (obj[firstColumn]) { - firstColumnValues.add(obj[firstColumn]); - } - if (firstColumnValues.size > 1) { - throwError("BOUNDARY", 400, "BOUNDARY_SHEET_FIRST_COLUMN_INVALID_ERROR", - `Data is invalid: The "${firstColumn}" column must contain only one unique value across all rows.`); - } - - for (const header of localizedHeadersOfBoundarySheet) { - const value = obj[header]; - - if (!value) { - // Mark that an empty value has been found for the first time - firstEmptyFound = true; - } else if (firstEmptyFound) { - // If a non-empty value is found after an empty value in the expected order, throw an error - throwError("BOUNDARY", 400, "BOUNDARY_SHEET_UPLOADED_INVALID_ERROR", - `Data is invalid in object at index ${index + 2}: Non-empty value for key "${header}" found after an empty value in the left.`); - } - } - }); -} - -export function validateEmptyActive(data: any, type: string, localizationMap?: { [key: string]: string }) { - let isActiveRowsZero = true; - const activeColumnName = createAndSearch?.[type]?.activeColumnName ? getLocalizedName(createAndSearch?.[type]?.activeColumnName, localizationMap) : null; - if(Array.isArray(data)){ - data.forEach((item: any) => { - const active = activeColumnName ? item[activeColumnName] : "Active"; - if (active == "Active") { - isActiveRowsZero = false; - return; - } - }); - } - else{ - // Data is not coming from a single sheet so no require for this active check - isActiveRowsZero = false; - } - if(isActiveRowsZero){ - throwError("COMMON", 400, "VALIDATION_ERROR", "At least one active row is required"); - } } @@ -1513,10 +1227,5 @@ export { validateDownloadRequest, validateTargetSheetData, immediateValidationForTargetSheet, - validateBoundaryOfResouces, - validateSearchProcessTracksRequest, - validateParent, - validateForRetry, - validateBoundarySheetDataInCreateFlow, - validateMicroplanRequest + validateBoundaryOfResouces } diff --git a/health-services/project-factory/src/server/validators/genericValidator.ts b/health-services/project-factory/src/server/validators/genericValidator.ts index 5c8ed266a53..426f1de67e7 100644 --- a/health-services/project-factory/src/server/validators/genericValidator.ts +++ b/health-services/project-factory/src/server/validators/genericValidator.ts @@ -2,14 +2,11 @@ import * as express from "express"; import { logger } from "../utils/logger"; import Ajv from "ajv"; +import config from "../config/index"; +import { httpRequest } from "../utils/request"; import { getBoundaryRelationshipData, throwError } from "../utils/genericUtils"; import { validateFilters } from "./campaignValidators"; import { generateRequestSchema } from "../config/models/generateRequestSchema"; -import { persistTrack } from "../utils/processTrackUtils"; -import { processTrackTypes, processTrackStatuses, campaignStatuses } from "../config/constants"; -import { validateMappingId } from "../utils/campaignMappingUtils"; -import { searchBoundaryRelationshipDefinition } from "../api/coreApis"; -import { BoundaryModels } from "../models"; // Function to validate data against a JSON schema function validateDataWithSchema(data: any, schema: any): { isValid: boolean; error: any | null | undefined } { @@ -33,11 +30,6 @@ function validateCampaignBodyViaSchema(schema: any, objectData: any) { const dataPath = error.dataPath.replace(/\//g, '.').replace(/^\./, ''); formattedErrorMessage = `${dataPath} ${error.message}`; } - else if (error?.instancePath) { - // Replace slash with dot and remove leading dot if present - const dataPath = error.instancePath.replace(/\//g, '.').replace(/^\./, ''); - formattedErrorMessage = `${dataPath} ${error.message}`; - } else { formattedErrorMessage = `${error.message}` } @@ -69,11 +61,6 @@ function validateBodyViaSchema(schema: any, objectData: any) { const dataPath = error.dataPath.replace(/\//g, '.').replace(/^\./, ''); formattedErrorMessage = `${dataPath} ${error.message}`; } - else if (error?.instancePath) { - // Replace slash with dot and remove leading dot if present - const dataPath = error.instancePath.replace(/\//g, '.').replace(/^\./, ''); - formattedErrorMessage = `${dataPath} ${error.message}`; - } else { formattedErrorMessage = `${error.message}` } @@ -128,40 +115,15 @@ async function validateCampaign(requestBody: any) { // Function to validate the entire campaign request async function validateCampaignRequest(requestBody: any) { - await persistTrack(requestBody?.Campaign?.id, processTrackTypes.validateMappingResource, processTrackStatuses.inprogress); - try { - if (requestBody?.Campaign) { - if (!requestBody?.Campaign?.tenantId) { - throwError("COMMON", 400, "VALIDATION_ERROR", "Enter TenantId"); - } - await validateCampaign(requestBody); - const id = requestBody?.Campaign?.id; - const campaignDetails = await validateMappingId(requestBody, id); - if (campaignDetails?.status == campaignStatuses.inprogress) { - logger.error("Campaign Already In Progress and Mapped"); - throwError("CAMPAIGN", 400, "CAMPAIGN_ALREADY_MAPPED"); - } - } - else { - throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign object is missing"); + if (requestBody?.Campaign) { + if (!requestBody?.Campaign?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter TenantId"); } - if (requestBody?.CampaignDetails) { - if (!requestBody?.CampaignDetails?.tenantId) { - throwError("COMMON", 400, "VALIDATION_ERROR", "Enter TenantId"); - } - if (!requestBody?.CampaignDetails?.id) { - throwError("COMMON", 400, "VALIDATION_ERROR", "Enter id in CampaignDetails"); - } - } - else { - throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails is missing"); - } - } catch (error: any) { - console.log(error) - await persistTrack(requestBody?.Campaign?.id, processTrackTypes.validateMappingResource, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); - throw new Error(error) + await validateCampaign(requestBody); + } + else { + throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign is required"); } - await persistTrack(requestBody?.Campaign?.id, processTrackTypes.validateMappingResource, processTrackStatuses.completed); } // Function to validate and update project response and its ID @@ -202,18 +164,18 @@ function validatedProjectResponseAndUpdateId(projectResponse: any, projectBody: // Function to validate the hierarchy type async function validateHierarchyType(request: any, hierarchyType: any, tenantId: any) { - - const BoundaryTypeHierarchySearchCriteria: BoundaryModels.BoundaryHierarchyDefinitionSearchCriteria={ - BoundaryTypeHierarchySearchCriteria:{ - tenantId, - hierarchyType + const searchBody = { + RequestInfo: request?.body?.RequestInfo, + BoundaryTypeHierarchySearchCriteria: { + "tenantId": tenantId, + "limit": 5, + "offset": 0, + "hierarchyType": hierarchyType } - }; - const response:BoundaryModels.BoundaryHierarchyDefinitionResponse =await searchBoundaryRelationshipDefinition(BoundaryTypeHierarchySearchCriteria); - + } + const response = await httpRequest(config.host.boundaryHost + config.paths.boundaryHierarchy, searchBody); if (response?.BoundaryHierarchy && Array.isArray(response?.BoundaryHierarchy) && response?.BoundaryHierarchy?.length > 0) { logger.info(`hierarchyType : ${hierarchyType} :: got validated`); - request.body.hierarchyType = response?.BoundaryHierarchy?.[0]; } else { throwError(`CAMPAIGN`, 400, "VALIDATION_ERROR", `hierarchyType ${hierarchyType} not found`); @@ -258,4 +220,4 @@ export { validateGenerateRequest, validateHierarchyType, validateCampaignBodyViaSchema -}; +}; \ No newline at end of file diff --git a/health-services/project-factory/src/server/validators/microplanValidators.ts b/health-services/project-factory/src/server/validators/microplanValidators.ts deleted file mode 100644 index 4bc9f35ebaf..00000000000 --- a/health-services/project-factory/src/server/validators/microplanValidators.ts +++ /dev/null @@ -1,323 +0,0 @@ -import { getBoundaryColumnName, getBoundaryTabName } from "../utils/boundaryUtils"; -import createAndSearch from "../config/createAndSearch"; -import { getLocalizedName } from "../utils/campaignUtils"; -import { resourceDataStatuses } from "../config/constants"; -import config from "../config"; -import { isMicroplanRequest } from "../utils/microplanUtils"; -import { throwError } from "../utils/genericUtils"; - -export function validatePhoneNumberSheetWise(datas: any[], localizationMap: any, rowMapping: any) { - for (const data of datas) { - const phoneColumn = getLocalizedName("HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER_MICROPLAN", localizationMap); - if (data[phoneColumn]) { - let phoneNumber = data[phoneColumn].toString(); - - // Check if the phone number is numeric and has exactly 10 digits - const isNumeric = /^\d+$/.test(phoneNumber); - if (phoneNumber.length !== 10 || !isNumeric) { - const row = data["!row#number!"]; - if (!rowMapping[row]) { - rowMapping[row] = []; - } - rowMapping[row].push("The ‘Contact number’ entered is invalid, it should be a 10-digit number and contain only digits. Please update and re-upload."); - } - } else { - const row = data["!row#number!"]; - if (!rowMapping[row]) { - rowMapping[row] = []; - } - rowMapping[row].push("The ‘Contact number’ is a mandatory field in the file. Please update and re-upload."); - } - } -} - - -export function validateEmailSheetWise(datas: any[], localizationMap: any, rowMapping: any) { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // Simple email regex pattern - - for (const data of datas) { - const emailColumn = getLocalizedName("HCM_ADMIN_CONSOLE_USER_EMAIL_MICROPLAN", localizationMap); - if (data[emailColumn]) { - let email = data[emailColumn].toString(); - - if (!emailRegex.test(email)) { // Validate email format with regex - const row = data["!row#number!"]; - if (!rowMapping[row]) { - rowMapping[row] = []; - } - rowMapping[row].push("The ‘Email’ entered is invalid. Please provide a valid email address and re-upload."); - } - } - } -} - -export function validateNameSheetWise(datas: any[], localizationMap: any, rowMapping: any) { - for (const data of datas) { - const nameColumn = getLocalizedName("HCM_ADMIN_CONSOLE_USER_NAME_MICROPLAN", localizationMap); - if (data[nameColumn]) { - var name = data[nameColumn]; - name = name.toString(); - const row = data["!row#number!"]; - - // Check name length - if (name.length > 128 || name.length < 2) { - if (!rowMapping[row]) { - rowMapping[row] = []; - } - rowMapping[row].push("The ‘Name’ should be between 2 to 128 characters. Please update and re-upload"); - } - else { - // Check if name contains at least one alphabetic character - const hasAlphabetic = /[a-zA-Z]/.test(name); - if (!hasAlphabetic) { - if (!rowMapping[row]) { - rowMapping[row] = []; - } - rowMapping[row].push("The ‘Name’ should contain at least one alphabetic character. Please update and re-upload"); - } - } - - } else { - const row = data["!row#number!"]; - if (!rowMapping[row]) { - rowMapping[row] = []; - } - rowMapping[row].push("The ‘Name’ is a mandatory field in the file. Please update and re-upload"); - } - } -} - - -export function validateUserForMicroplan(data: any, sheetName: any, request: any, errorMap: any, newSchema: any, rowMapping: any, localizationMap: any) { - if (data?.length > 0) { - validatePhoneNumberSheetWise(data, localizationMap, rowMapping); - validateEmailSheetWise(data, localizationMap, rowMapping); - validateNameSheetWise(data, localizationMap, rowMapping); - validateUniqueSheetWise(newSchema, data, request, rowMapping, localizationMap); - } - else { - errorMap[sheetName] = { 2: ["Data rows cannot be empty"] }; - } -} - -export function validateUniqueSheetWise(schema: any, data: any[], request: any, rowMapping: any, localizationMap: any) { - if (schema?.unique) { - const uniqueElements = schema.unique; - - for (const element of uniqueElements) { - const uniqueMap = new Map(); - - // Iterate over each data object and check uniqueness - for (const item of data) { - const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName; - const localizedUniqueIdentifierColumnName = getLocalizedName(uniqueIdentifierColumnName, localizationMap); - const value = item[element]; - const rowNum = item['!row#number!']; - if (!localizedUniqueIdentifierColumnName || !item[localizedUniqueIdentifierColumnName] && value != undefined) { - if (uniqueMap.has(value)) { - if (!rowMapping[rowNum]) { - rowMapping[rowNum] = []; - } - rowMapping[rowNum].push(`Duplicate value '${value}' found for '${element}'`); - } - // Add the value to the map - uniqueMap.set(value, rowNum); - } - } - } - } -} - -export function validateTargetsForMicroplanCampaigns(data: any, errors: any, localizedTargetColumnNames: any, localizationMap?: { [key: string]: string }) { - for (const key in data) { - if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { - if (Array.isArray(data[key])) { - const boundaryData = data[key]; - boundaryData.forEach((obj: any, index: number) => { - var totalTarget = 0, totalTargetSumFromColumns = 0; - for (let i = 0; i < localizedTargetColumnNames.length; i++) { - const targetColumn = localizedTargetColumnNames[i]; - const target = obj[targetColumn]; - if (target !== 0 && !target) { - errors.push({ - status: "INVALID", - rowNumber: obj["!row#number!"], - errorDetails: `Data in column '${targetColumn}' can’t be empty, please update the data and re-upload`, - sheetName: key - }); - } else if (typeof target !== 'number') { - errors.push({ - status: "INVALID", - rowNumber: obj["!row#number!"], - errorDetails: `Data in column '${targetColumn}' must be a whole number from 1 to 100000000. Please update the data and re-upload.`, - sheetName: key - }); - } else if (target < 1 || target > 100000000) { - errors.push({ - status: "INVALID", - rowNumber: obj["!row#number!"], - errorDetails: `Data in column '${targetColumn}' must be a whole number from 1 to 100000000. Please update the data and re-upload.`, - sheetName: key - }); - } else if (!Number.isInteger(target)) { - errors.push({ - status: "INVALID", - rowNumber: obj["!row#number!"], - errorDetails: `Data in column '${targetColumn}' must be a whole number from 1 to 100000000. Please update the data and re-upload.`, - sheetName: key - }); - } - if (i == 0) { - totalTarget = target; - } - else { - totalTargetSumFromColumns += target; - } - } - if (totalTargetSumFromColumns > totalTarget) { - errors.push({ - status: "INVALID", - rowNumber: obj["!row#number!"], - errorDetails: `Data in other target columns must be less than or equal to '${localizedTargetColumnNames[0]}'`, - sheetName: key - }); - } - }); - } - } - } -} - -export function validateLatLongForMicroplanCampaigns(data: any, errors: any, localizationMap?: { [key: string]: string }) { - for (const key in data) { - if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { - if (Array.isArray(data[key])) { - const boundaryData = data[key]; - boundaryData.forEach((obj: any, index: number) => { - for (const column of Object.keys(obj)) { - if (column.toLowerCase().includes('latitude') || column.toLowerCase().includes('longitude')) { - const value = obj[column]; - if (typeof value !== 'number') { - errors.push({ - status: "INVALID", - rowNumber: obj["!row#number!"], - errorDetails: `Data in column '${column}' must comply with the guideline structure, please update the data and re-upload`, - sheetName: key - }); - } - } - } - }); - } - } - } -} - - -function validateLatLongForFacility(data: any, errors: any) { - for (const column of Object.keys(data)) { - if (column.toLowerCase().includes('latitude') || column.toLowerCase().includes('longitude')) { - const value = data[column]; - if (typeof value !== 'number') { - errors.push({ - status: "INVALID", - rowNumber: data["!row#number!"], - errorDetails: `Data in column '${column}' must comply with the guideline structure, please update the data and re-upload` - }); - } - } - } -}; - -export function validateMicroplanFacility(request: any, data: any, localizationMap: any) { - const uniqueIdentifierColumnName = getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap); - const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; - var errors: any = [] - data.forEach((item: any) => { - if (activeColumnName) { - if (!item?.[activeColumnName]) { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${activeColumnName} column can’t be empty, please update the data and re-upload` }); - } - else if (item?.[activeColumnName] != "Active" && item?.[activeColumnName] != "Inactive") { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${activeColumnName} column must be equal to one of the allowed values. Allowed values are Active, Inactive` }); - } - } - const active = activeColumnName ? item[activeColumnName] : "Active"; - if (active == "Active" || !item?.[uniqueIdentifierColumnName]) { - enrichErrorForFcailityMicroplan(request, item, errors, localizationMap); - validateLatLongForFacility(item, errors); - } - }); - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; - if (request?.body?.sheetErrorDetails && Array.isArray(request?.body?.sheetErrorDetails) && request?.body?.sheetErrorDetails?.length > 0) { - request.body.ResourceDetails.status = resourceDataStatuses.invalid; - } -} - -function enrichErrorForFcailityMicroplan(request: any, item: any, errors: any = [], localizationMap?: { [key: string]: string }) { - const projectType = request?.body?.projectTypeCode; - const nameColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_NAME_MICROPLAN", localizationMap); - if (!item?.[nameColumn]) { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${nameColumn} column can’t be empty, please update the data and re-upload` }) - } - const facilityTypeColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_TYPE_MICROPLAN", localizationMap); - if (!item?.[facilityTypeColumn]) { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityTypeColumn} column can’t be empty, please update the data and re-upload` }) - } - const faciltyStatusColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_STATUS_MICROPLAN", localizationMap); - if (!item?.[faciltyStatusColumn]) { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${faciltyStatusColumn} column can’t be empty, please update the data and re-upload` }) - } - const facilityCapacityColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN_${projectType}`, localizationMap); - if (!item?.[facilityCapacityColumn]) { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column can’t be empty or zero, please update the data and re-upload` }) - } - else if (typeof (item?.[facilityCapacityColumn]) != "number") { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column must be a number in between 1 and 100000000` }) - } - else if (item?.[facilityCapacityColumn] < 1 || item?.[facilityCapacityColumn] > 100000000) { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column must be a number in between 1 and 100000000` }) - } - const fixedPostColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_FIXED_POST_MICROPLAN", localizationMap); - if (request?.body?.showFixedPost && !item?.[fixedPostColumn]) { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${fixedPostColumn} column can’t be empty, please update the data and re-upload` }) - } - const boundaryColumn = getLocalizedName("HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN", localizationMap); - if (!item?.[boundaryColumn]) { - errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${boundaryColumn} column can’t be empty, please update the data and re-upload` }) - } -} - -export function validateFacilityBoundaryForLowestLevel(request: any, boundaries: any, rowData: any, errors: any = [], localizationMap?: { [key: string]: string }) { - if (request?.body?.ResourceDetails?.type == "facility" && request?.body?.ResourceDetails?.additionalDetails?.source == "microplan") { - const hierarchy = request?.body?.hierarchyType?.boundaryHierarchy - const lastLevel = hierarchy?.[hierarchy.length - 1]?.boundaryType - for (const data of rowData?.boundaryCodes) { - const boundaryFromBoundariesType = boundaries.find((boundary: any) => boundary.code == data)?.type - if (boundaryFromBoundariesType != lastLevel) { - errors.push({ status: "INVALID", rowNumber: rowData?.rowNumber, errorDetails: `${data} is not a ${lastLevel} level boundary` }) - } - } - } -} - - - -export async function validateExtraBoundariesForMicroplan(request: any, dataFromSheet: any, localizationMap: any) { - if (await isMicroplanRequest(request)) { - const campaignBoundariesSet = new Set(request?.body?.campaignBoundaries?.map((boundary: any) => boundary.code)); - for (const key in dataFromSheet) { - if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { - if (Object.prototype.hasOwnProperty.call(dataFromSheet, key)) { - const dataArray = (dataFromSheet as { [key: string]: any[] })[key]; - for (const boundaryRow of dataArray) { - const boundaryCode = boundaryRow[getLocalizedName(getBoundaryColumnName(), localizationMap)]; - if (!campaignBoundariesSet.has(boundaryCode)) { - throwError("COMMON", 400, "VALIDATION_ERROR", `Some boundaries in uploaded sheet are not present in campaign boundaries. Please upload from downloaded template only.`); - } - } - } - } - } - } -} \ No newline at end of file diff --git a/health-services/project-factory/tsconfig.debug.json b/health-services/project-factory/tsconfig.debug.json deleted file mode 100644 index 3d14147fd18..00000000000 --- a/health-services/project-factory/tsconfig.debug.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "compilerOptions": { - "skipLibCheck": true, - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./dist/", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - "strictNullChecks": true, /* Enable strict null checks. */ - "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - /* Additional Checks */ - "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - /* Module Resolution Options */ - "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - "typeRoots": [ - "./node_modules/@types" - ], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - /* Source Map Options */ - // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - }, - "include": [ - "./src/**/*" - ], - "exclude": [ - "node_modules", - "**/*.test.ts" - ] -} \ No newline at end of file diff --git a/health-services/project-factory/tsconfig.json b/health-services/project-factory/tsconfig.json index 8843b6680c1..5afabc37a6b 100644 --- a/health-services/project-factory/tsconfig.json +++ b/health-services/project-factory/tsconfig.json @@ -63,4 +63,4 @@ "node_modules", "**/*.test.ts" ] -} +} \ No newline at end of file diff --git a/health-services/project-factory/yarn.lock b/health-services/project-factory/yarn.lock index 2f75dbe7f43..0584dc93095 100644 --- a/health-services/project-factory/yarn.lock +++ b/health-services/project-factory/yarn.lock @@ -2,15 +2,35 @@ # yarn lockfile v1 +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + "@ampproject/remapping@^2.2.0": version "2.3.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.7": +"@babel/code-frame@^7.0.0": + version "7.12.11" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5": + version "7.24.2" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== + dependencies: + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" + +"@babel/code-frame@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== @@ -18,53 +38,75 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/compat-data@^7.25.2": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" - integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== +"@babel/compat-data@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.7.tgz#d23bbea508c3883ba8251fb4164982c36ea577ed" + integrity sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw== "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" - integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.7.tgz#b676450141e0b52a3d43bc91da86aa608f950ac4" + integrity sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g== dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.0" - "@babel/helper-compilation-targets" "^7.25.2" - "@babel/helper-module-transforms" "^7.25.2" - "@babel/helpers" "^7.25.0" - "@babel/parser" "^7.25.0" - "@babel/template" "^7.25.0" - "@babel/traverse" "^7.25.2" - "@babel/types" "^7.25.2" + "@babel/generator" "^7.24.7" + "@babel/helper-compilation-targets" "^7.24.7" + "@babel/helper-module-transforms" "^7.24.7" + "@babel/helpers" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/template" "^7.24.7" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.25.0", "@babel/generator@^7.25.6", "@babel/generator@^7.7.2": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" - integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== +"@babel/generator@^7.24.7", "@babel/generator@^7.7.2": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" + integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== dependencies: - "@babel/types" "^7.25.6" + "@babel/types" "^7.24.7" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" - integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== +"@babel/helper-compilation-targets@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz#4eb6c4a80d6ffeac25ab8cd9a21b5dfa48d503a9" + integrity sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg== dependencies: - "@babel/compat-data" "^7.25.2" - "@babel/helper-validator-option" "^7.24.8" - browserslist "^4.23.1" + "@babel/compat-data" "^7.24.7" + "@babel/helper-validator-option" "^7.24.7" + browserslist "^4.22.2" lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-environment-visitor@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" + integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-function-name@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" + integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== + dependencies: + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-hoist-variables@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" + integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ== + dependencies: + "@babel/types" "^7.24.7" + "@babel/helper-module-imports@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" @@ -73,20 +115,21 @@ "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/helper-module-transforms@^7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" - integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== +"@babel/helper-module-transforms@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz#31b6c9a2930679498db65b685b1698bfd6c7daf8" + integrity sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ== dependencies: + "@babel/helper-environment-visitor" "^7.24.7" "@babel/helper-module-imports" "^7.24.7" "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-split-export-declaration" "^7.24.7" "@babel/helper-validator-identifier" "^7.24.7" - "@babel/traverse" "^7.25.2" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.8.0": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" - integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": + version "7.24.0" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz" + integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== "@babel/helper-simple-access@^7.24.7": version "7.24.7" @@ -96,28 +139,55 @@ "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/helper-string-parser@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" - integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== +"@babel/helper-split-export-declaration@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" + integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-string-parser@^7.23.4": + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz" + integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== + +"@babel/helper-string-parser@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" + integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== "@babel/helper-validator-identifier@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== -"@babel/helper-validator-option@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" - integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== +"@babel/helper-validator-option@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz#24c3bb77c7a425d1742eec8fb433b5a1b38e62f6" + integrity sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw== + +"@babel/helpers@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.7.tgz#aa2ccda29f62185acb5d42fb4a3a1b1082107416" + integrity sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg== + dependencies: + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" -"@babel/helpers@^7.25.0": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" - integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== +"@babel/highlight@^7.10.4", "@babel/highlight@^7.24.2": + version "7.24.2" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz" + integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== dependencies: - "@babel/template" "^7.25.0" - "@babel/types" "^7.25.6" + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" "@babel/highlight@^7.24.7": version "7.24.7" @@ -129,183 +199,181 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.25.6": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" - integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== - dependencies: - "@babel/types" "^7.25.6" +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" + integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-bigint@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.12.13": +"@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-import-attributes@^7.24.7": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz#6d4c78f042db0e82fd6436cd65fec5dc78ad2bde" - integrity sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ== - dependencies: - "@babel/helper-plugin-utils" "^7.24.8" - -"@babel/plugin-syntax-import-meta@^7.10.4": +"@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d" - integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ== + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz" + integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== dependencies: - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.4": +"@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-top-level-await@^7.14.5": +"@babel/plugin-syntax-top-level-await@^7.8.3": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz#04db9ce5a9043d9c635e75ae7969a2cd50ca97ff" - integrity sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg== + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz" + integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== dependencies: - "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/template@^7.25.0", "@babel/template@^7.3.3": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" - integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== +"@babel/template@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" + integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== dependencies: "@babel/code-frame" "^7.24.7" - "@babel/parser" "^7.25.0" - "@babel/types" "^7.25.0" + "@babel/parser" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/template@^7.3.3": + version "7.24.0" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz" + integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/parser" "^7.24.0" + "@babel/types" "^7.24.0" -"@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" - integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== +"@babel/traverse@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5" + integrity sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA== dependencies: "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.6" - "@babel/parser" "^7.25.6" - "@babel/template" "^7.25.0" - "@babel/types" "^7.25.6" + "@babel/generator" "^7.24.7" + "@babel/helper-environment-visitor" "^7.24.7" + "@babel/helper-function-name" "^7.24.7" + "@babel/helper-hoist-variables" "^7.24.7" + "@babel/helper-split-export-declaration" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/types" "^7.24.7" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6", "@babel/types@^7.3.3": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" - integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.0", "@babel/types@^7.3.3": + version "7.24.0" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz" + integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== dependencies: - "@babel/helper-string-parser" "^7.24.8" + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@babel/types@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2" + integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q== + dependencies: + "@babel/helper-string-parser" "^7.24.7" "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== "@colors/colors@1.6.0", "@colors/colors@^1.6.0": version "1.6.0" - resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" + resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz" integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: "@jridgewell/trace-mapping" "0.3.9" "@dabh/diagnostics@^2.0.2": version "2.0.3" - resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" + resolved "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz" integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== dependencies: colorspace "1.1.x" @@ -314,7 +382,7 @@ "@eslint/eslintrc@^0.2.2": version "0.2.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz" integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ== dependencies: ajv "^6.12.4" @@ -330,7 +398,7 @@ "@fast-csv/format@4.3.5": version "4.3.5" - resolved "https://registry.yarnpkg.com/@fast-csv/format/-/format-4.3.5.tgz#90d83d1b47b6aaf67be70d6118f84f3e12ee1ff3" + resolved "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz" integrity sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A== dependencies: "@types/node" "^14.0.1" @@ -342,7 +410,7 @@ "@fast-csv/parse@4.3.6": version "4.3.6" - resolved "https://registry.yarnpkg.com/@fast-csv/parse/-/parse-4.3.6.tgz#ee47d0640ca0291034c7aa94039a744cfb019264" + resolved "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz" integrity sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA== dependencies: "@types/node" "^14.0.1" @@ -360,7 +428,7 @@ "@isaacs/cliui@^8.0.2": version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== dependencies: string-width "^5.1.2" @@ -372,7 +440,7 @@ "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: camelcase "^5.3.1" @@ -383,12 +451,12 @@ "@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== "@jest/console@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + resolved "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz" integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: "@jest/types" "^29.6.3" @@ -400,7 +468,7 @@ "@jest/core@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + resolved "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz" integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== dependencies: "@jest/console" "^29.7.0" @@ -434,7 +502,7 @@ "@jest/environment@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz" integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== dependencies: "@jest/fake-timers" "^29.7.0" @@ -444,14 +512,14 @@ "@jest/expect-utils@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz" integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== dependencies: jest-get-type "^29.6.3" "@jest/expect@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz" integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== dependencies: expect "^29.7.0" @@ -459,7 +527,7 @@ "@jest/fake-timers@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz" integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== dependencies: "@jest/types" "^29.6.3" @@ -471,7 +539,7 @@ "@jest/globals@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz" integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: "@jest/environment" "^29.7.0" @@ -481,7 +549,7 @@ "@jest/reporters@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz" integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" @@ -511,14 +579,14 @@ "@jest/schemas@^29.6.3": version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== dependencies: "@sinclair/typebox" "^0.27.8" "@jest/source-map@^29.6.3": version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz" integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: "@jridgewell/trace-mapping" "^0.3.18" @@ -527,7 +595,7 @@ "@jest/test-result@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz" integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: "@jest/console" "^29.7.0" @@ -537,7 +605,7 @@ "@jest/test-sequencer@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz" integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== dependencies: "@jest/test-result" "^29.7.0" @@ -547,7 +615,7 @@ "@jest/transform@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz" integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: "@babel/core" "^7.11.6" @@ -568,7 +636,7 @@ "@jest/types@^29.6.3": version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: "@jest/schemas" "^29.6.3" @@ -580,7 +648,7 @@ "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== dependencies: "@jridgewell/set-array" "^1.2.1" @@ -589,22 +657,22 @@ "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/set-array@^1.2.1": version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + version "1.4.15" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" @@ -612,7 +680,7 @@ "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== dependencies: "@jridgewell/resolve-uri" "^3.1.0" @@ -620,7 +688,7 @@ "@npmcli/agent@^2.0.0": version "2.2.2" - resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-2.2.2.tgz#967604918e62f620a648c7975461c9c9e74fc5d5" + resolved "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz" integrity sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og== dependencies: agent-base "^7.1.0" @@ -630,59 +698,59 @@ socks-proxy-agent "^8.0.3" "@npmcli/fs@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-3.1.1.tgz#59cdaa5adca95d135fc00f2bb53f5771575ce726" - integrity sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg== + version "3.1.0" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz" + integrity sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w== dependencies: semver "^7.3.5" "@pkgjs/parseargs@^0.11.0": version "0.11.0" - resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@sinclair/typebox@^0.27.8": version "0.27.8" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== "@sinonjs/commons@^3.0.0": version "3.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz" integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" "@sinonjs/fake-timers@^10.0.2": version "10.3.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz" integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== dependencies: "@sinonjs/commons" "^3.0.0" "@tsconfig/node10@^1.0.7": version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz" integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== "@tsconfig/node14@^1.0.0": version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@types/babel__core@^7.1.14": version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz" integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== dependencies: "@babel/parser" "^7.20.7" @@ -693,29 +761,29 @@ "@types/babel__generator@*": version "7.6.8" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz" integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": version "7.4.4" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz" integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.20.6" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" - integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== + version "7.20.5" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz" + integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== dependencies: "@babel/types" "^7.20.7" "@types/body-parser@*": version "1.19.5" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz" integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== dependencies: "@types/connect" "*" @@ -723,22 +791,22 @@ "@types/compression@1.7.5": version "1.7.5" - resolved "https://registry.yarnpkg.com/@types/compression/-/compression-1.7.5.tgz#0f80efef6eb031be57b12221c4ba6bc3577808f7" + resolved "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz" integrity sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg== dependencies: "@types/express" "*" "@types/connect@*": version "3.4.38" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== dependencies: "@types/node" "*" "@types/express-serve-static-core@^4.17.33": - version "4.19.5" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz#218064e321126fcf9048d1ca25dd2465da55d9c6" - integrity sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg== + version "4.17.43" + resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz" + integrity sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg== dependencies: "@types/node" "*" "@types/qs" "*" @@ -747,7 +815,7 @@ "@types/express@*", "@types/express@4.17.21": version "4.17.21" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + resolved "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz" integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== dependencies: "@types/body-parser" "*" @@ -757,64 +825,64 @@ "@types/graceful-fs@^4.1.3": version "4.1.9" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz" integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== dependencies: "@types/node" "*" "@types/hash-sum@1.0.2": version "1.0.2" - resolved "https://registry.yarnpkg.com/@types/hash-sum/-/hash-sum-1.0.2.tgz#32e6e4343ee25914b2a3822f27e8e641ca534f63" + resolved "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz" integrity sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw== "@types/helmet@0.0.47": version "0.0.47" - resolved "https://registry.yarnpkg.com/@types/helmet/-/helmet-0.0.47.tgz#ec5161541b649142205b7c558bca14801c5ce129" + resolved "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.47.tgz" integrity sha512-TcHA/djjdUtrMtq/QAayVLrsgjNNZ1Uhtz0KhfH01mrmjH44E54DA1A0HNbwW0H/NBFqV+tGMo85ACuEhMXcdg== dependencies: "@types/express" "*" "@types/http-errors@*": version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== "@types/http-proxy-middleware@^1.0.0": version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz#4370a52766782e9c4f0be2ef79c3dd47aef5f428" + resolved "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz" integrity sha512-/s8lFX6rT43hSPqjjD8KNuu0SkPKY7uIdR6u9DCxVqCRhAvfKxGbVOixJsAT2mdpSnCyrGFAGoB39KFh6tmRxw== dependencies: http-proxy-middleware "*" -"@types/http-proxy@^1.17.15": - version "1.17.15" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36" - integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ== +"@types/http-proxy@^1.17.10": + version "1.17.14" + resolved "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz" + integrity sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w== dependencies: "@types/node" "*" "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz" integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== "@types/istanbul-lib-report@*": version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz" integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz" integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== dependencies: "@types/istanbul-lib-report" "*" "@types/jaeger-client@^3.18.7": version "3.18.7" - resolved "https://registry.yarnpkg.com/@types/jaeger-client/-/jaeger-client-3.18.7.tgz#19315eb1616d85b84210da5df01b4a62c219c5b0" + resolved "https://registry.npmjs.org/@types/jaeger-client/-/jaeger-client-3.18.7.tgz" integrity sha512-ktEWbcM8faJY5UNEmffnvavjIJ9noNCD7clD9hAZIuQt6QMv0T97kiveH0mbvBNr9SPZXmkidOu/3UWgSy89tQ== dependencies: "@types/node" "*" @@ -823,51 +891,39 @@ "@types/jest@29.5.12": version "29.5.12" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" + resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz" integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== dependencies: expect "^29.0.0" pretty-format "^29.0.0" -"@types/lodash@^4.17.5": - version "4.17.7" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.7.tgz#2f776bcb53adc9e13b2c0dfd493dfcbd7de43612" - integrity sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA== - "@types/mime@^1": version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz" integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== "@types/morgan@1.9.9": version "1.9.9" - resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.9.9.tgz#d60dec3979e16c203a000159daa07d3fb7270d7f" + resolved "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz" integrity sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ== dependencies: "@types/node" "*" -"@types/node@*": - version "22.5.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.5.tgz#52f939dd0f65fc552a4ad0b392f3c466cc5d7a44" - integrity sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA== - dependencies: - undici-types "~6.19.2" - -"@types/node@20.11.29": +"@types/node@*", "@types/node@20.11.29": version "20.11.29" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.29.tgz#431253cede34f392d6aaf7acad427b9c23aa60f6" + resolved "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz" integrity sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA== dependencies: undici-types "~5.26.4" "@types/node@^14.0.1": version "14.18.63" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b" + resolved "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz" integrity sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ== "@types/pg@8.11.3": version "8.11.3" - resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.11.3.tgz#f55c81b5ecdb6901636946eccfc7aac5dfc6b840" + resolved "https://registry.npmjs.org/@types/pg/-/pg-8.11.3.tgz" integrity sha512-xocw4LvpDcj/Ta7bN52tLZm34mso5SZ0Q8fVC0UtD8s85Itip3YHvBeYZhBmC0OThpdOujHsxXtRbEIRxqXPXg== dependencies: "@types/node" "*" @@ -875,18 +931,18 @@ pg-types "^4.0.1" "@types/qs@*": - version "6.9.16" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" - integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== + version "6.9.14" + resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz" + integrity sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA== "@types/range-parser@*": version "1.2.7" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz" integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== "@types/send@*": version "0.17.4" - resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz" integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== dependencies: "@types/mime" "^1" @@ -894,7 +950,7 @@ "@types/serve-static@*": version "1.15.7" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz" integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: "@types/http-errors" "*" @@ -903,56 +959,56 @@ "@types/stack-utils@^2.0.0": version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== "@types/strip-bom@^3.0.0": version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" + resolved "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ== "@types/strip-json-comments@0.0.30": version "0.0.30" - resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" + resolved "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz" integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== "@types/triple-beam@^1.3.2": version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" + resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz" integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== "@types/uuid@9.0.8": version "9.0.8" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz" integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== "@types/xlsx@0.0.36": version "0.0.36" - resolved "https://registry.yarnpkg.com/@types/xlsx/-/xlsx-0.0.36.tgz#b5062003e5c5374ab4f08fdd3bf69da4d4013af8" + resolved "https://registry.npmjs.org/@types/xlsx/-/xlsx-0.0.36.tgz" integrity sha512-mvfrKiKKMErQzLMF8ElYEH21qxWCZtN59pHhWGmWCWFJStYdMWjkDSAy6mGowFxHXaXZWe5/TW7pBUiWclIVOw== dependencies: xlsx "*" "@types/yargs-parser@*": version "21.0.3" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz" integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^17.0.8": - version "17.0.33" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" - integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== + version "17.0.32" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== dependencies: "@types/yargs-parser" "*" abbrev@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz" integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: mime-types "~2.1.34" @@ -960,41 +1016,39 @@ accepts@~1.3.5, accepts@~1.3.8: acorn-jsx@^5.3.1: version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^8.1.1: - version "8.3.4" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" - integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== - dependencies: - acorn "^8.11.0" + version "8.3.2" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== acorn@^7.4.0: version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.11.0, acorn@^8.4.1: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== +acorn@^8.4.1: + version "8.11.3" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== adler-32@~1.3.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2" + resolved "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz" integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A== agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1: version "7.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz" integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== dependencies: debug "^4.3.4" aggregate-error@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== dependencies: clean-stack "^2.0.0" @@ -1002,12 +1056,12 @@ aggregate-error@^3.0.0: ajv-errors@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-3.0.0.tgz#e54f299f3a3d30fe144161e5f0d8d51196c527bc" + resolved "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz" integrity sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ== ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" @@ -1016,74 +1070,74 @@ ajv@^6.10.0, ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1, ajv@^8.16.0: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" - integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + version "8.16.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz" + integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== dependencies: fast-deep-equal "^3.1.3" - fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" + uri-js "^4.4.1" ansi-color@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/ansi-color/-/ansi-color-0.2.1.tgz#3e75c037475217544ed763a8db5709fa9ae5bf9a" + resolved "https://registry.npmjs.org/ansi-color/-/ansi-color-0.2.1.tgz" integrity sha512-bF6xLaZBLpOQzgYUtYEhJx090nPSZk1BQ/q2oyBK9aMMcJHzx9uXGCjI2Y+LebsN4Jwoykr0V9whbPiogdyHoQ== ansi-colors@^4.1.1: version "4.1.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== ansi-escapes@^4.2.1: version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" - integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + version "6.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" ansi-styles@^5.0.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== ansi-styles@^6.1.0: version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" @@ -1091,12 +1145,12 @@ anymatch@^3.0.3, anymatch@~3.1.2: aproba@^1.0.3: version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== archiver-utils@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" + resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz" integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== dependencies: glob "^7.1.4" @@ -1112,7 +1166,7 @@ archiver-utils@^2.1.0: archiver-utils@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-3.0.4.tgz#a0d201f1cf8fce7af3b5a05aea0a337329e96ec7" + resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz" integrity sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw== dependencies: glob "^7.2.3" @@ -1128,7 +1182,7 @@ archiver-utils@^3.0.4: archiver@^5.0.0: version "5.3.2" - resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.2.tgz#99991d5957e53bd0303a392979276ac4ddccf3b0" + resolved "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz" integrity sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw== dependencies: archiver-utils "^2.1.0" @@ -1141,7 +1195,7 @@ archiver@^5.0.0: are-we-there-yet@~1.1.2: version "1.1.7" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz" integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== dependencies: delegates "^1.0.0" @@ -1149,46 +1203,46 @@ are-we-there-yet@~1.1.2: arg@^4.1.0: version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== argparse@^1.0.7: version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== astral-regex@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async@^2.6.2: version "2.6.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + resolved "https://registry.npmjs.org/async/-/async-2.6.4.tgz" integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== dependencies: lodash "^4.17.14" async@^3.2.3, async@^3.2.4: - version "3.2.6" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" - integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + version "3.2.5" + resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== axios@1.6.8: version "1.6.8" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" + resolved "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz" integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== dependencies: follow-redirects "^1.15.6" @@ -1197,7 +1251,7 @@ axios@1.6.8: babel-jest@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz" integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== dependencies: "@jest/transform" "^29.7.0" @@ -1210,7 +1264,7 @@ babel-jest@^29.7.0: babel-plugin-istanbul@^6.1.1: version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -1221,7 +1275,7 @@ babel-plugin-istanbul@^6.1.1: babel-plugin-jest-hoist@^29.6.3: version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz" integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" @@ -1230,29 +1284,26 @@ babel-plugin-jest-hoist@^29.6.3: "@types/babel__traverse" "^7.0.6" babel-preset-current-node-syntax@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" - integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== + version "1.0.1" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-import-attributes" "^7.24.7" - "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.8.3" babel-preset-jest@^29.6.3: version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz" integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: babel-plugin-jest-hoist "^29.6.3" @@ -1260,34 +1311,34 @@ babel-preset-jest@^29.6.3: balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-js@^1.3.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== basic-auth@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" + resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz" integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== dependencies: safe-buffer "5.1.2" big-integer@^1.6.17: version "1.6.52" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" + resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz" integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== binary-extensions@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== binary@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" + resolved "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz" integrity sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg== dependencies: buffers "~0.1.1" @@ -1295,19 +1346,19 @@ binary@~0.3.0: bindings@^1.3.1: version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== dependencies: file-uri-to-path "1.0.0" bintrees@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.2.tgz#49f896d6e858a4a499df85c38fb399b9aff840f8" + resolved "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz" integrity sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw== bl@^1.0.0: version "1.2.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" + resolved "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz" integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== dependencies: readable-stream "^2.3.5" @@ -1315,7 +1366,7 @@ bl@^1.0.0: bl@^2.2.0: version "2.2.1" - resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5" + resolved "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz" integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g== dependencies: readable-stream "^2.3.5" @@ -1323,7 +1374,7 @@ bl@^2.2.0: bl@^4.0.3: version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== dependencies: buffer "^5.5.0" @@ -1332,13 +1383,13 @@ bl@^4.0.3: bluebird@~3.4.1: version "3.4.7" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz" integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA== -body-parser@1.20.3, body-parser@^1.20.2: - version "1.20.3" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" - integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== +body-parser@1.20.2, body-parser@^1.20.2: + version "1.20.2" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -1348,14 +1399,14 @@ body-parser@1.20.3, body-parser@^1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.13.0" + qs "6.11.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -1363,43 +1414,43 @@ brace-expansion@^1.1.7: brace-expansion@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" -braces@^3.0.3, braces@~3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: - fill-range "^7.1.1" + fill-range "^7.0.1" -browserslist@^4.23.1: - version "4.23.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" - integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== +browserslist@^4.22.2: + version "4.23.0" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" + integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== dependencies: - caniuse-lite "^1.0.30001646" - electron-to-chromium "^1.5.4" - node-releases "^2.0.18" - update-browserslist-db "^1.1.0" + caniuse-lite "^1.0.30001587" + electron-to-chromium "^1.4.668" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" bser@2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== dependencies: node-int64 "^0.4.0" buffer-alloc-unsafe@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz" integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== buffer-alloc@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz" integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== dependencies: buffer-alloc-unsafe "^1.1.0" @@ -1407,27 +1458,27 @@ buffer-alloc@^1.2.0: buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.5: version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== buffer-fill@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz" integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== buffer-from@^1.0.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer-indexof-polyfill@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz#d2732135c5999c64b277fcf9b1abe3498254729c" + resolved "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz" integrity sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A== buffer@^5.5.0: version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: base64-js "^1.3.1" @@ -1435,19 +1486,19 @@ buffer@^5.5.0: buffermaker@~1.2.0: version "1.2.1" - resolved "https://registry.yarnpkg.com/buffermaker/-/buffermaker-1.2.1.tgz#0631f92b891a84b750f1036491ac857c734429f4" + resolved "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.1.tgz" integrity sha512-IdnyU2jDHU65U63JuVQNTHiWjPRH0CS3aYd/WPaEwyX84rFdukhOduAVb1jwUScmb5X0JWPw8NZOrhoLMiyAHQ== dependencies: long "1.1.2" buffers@~0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" + resolved "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz" integrity sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ== bufrw@^1.2.1: version "1.4.0" - resolved "https://registry.yarnpkg.com/bufrw/-/bufrw-1.4.0.tgz#58a294ca0bd9ebc880be83001d749706fc996499" + resolved "https://registry.npmjs.org/bufrw/-/bufrw-1.4.0.tgz" integrity sha512-sWm8iPbqvL9+5SiYxXH73UOkyEbGQg7kyHQmReF89WJHQJw2eV4P/yZ0E+b71cczJ4pPobVhXxgQcmfSTgGHxQ== dependencies: ansi-color "^0.2.1" @@ -1457,18 +1508,18 @@ bufrw@^1.2.1: bytes@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== bytes@3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== cacache@^18.0.0: - version "18.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.4.tgz#4601d7578dadb59c66044e157d02a3314682d6a5" - integrity sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ== + version "18.0.2" + resolved "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz" + integrity sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw== dependencies: "@npmcli/fs" "^3.1.0" fs-minipass "^3.0.0" @@ -1485,7 +1536,7 @@ cacache@^18.0.0: call-bind@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz" integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: es-define-property "^1.0.0" @@ -1496,27 +1547,27 @@ call-bind@^1.0.7: callsites@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== camelcase@^5.3.1: version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== camelcase@^6.2.0: version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001646: - version "1.0.30001663" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz#1529a723505e429fdfd49532e9fc42273ba7fed7" - integrity sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA== +caniuse-lite@^1.0.30001587: + version "1.0.30001605" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz" + integrity sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ== cfb@^1.1.3, cfb@~1.2.1: version "1.2.2" - resolved "https://registry.yarnpkg.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44" + resolved "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz" integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA== dependencies: adler-32 "~1.3.0" @@ -1524,14 +1575,14 @@ cfb@^1.1.3, cfb@~1.2.1: chainsaw@~0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" + resolved "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz" integrity sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ== dependencies: traverse ">=0.3.0 <0.4" chalk@^2.4.2: version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" @@ -1540,7 +1591,7 @@ chalk@^2.4.2: chalk@^4.0.0: version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -1548,12 +1599,12 @@ chalk@^4.0.0: char-regex@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== chokidar@^3.5.1: version "3.6.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" @@ -1568,32 +1619,32 @@ chokidar@^3.5.1: chownr@^1.0.1: version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== chownr@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== ci-info@^3.2.0: version "3.9.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" - integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== + version "1.2.3" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== clean-stack@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== cliui@^8.0.1: version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== dependencies: string-width "^4.2.0" @@ -1602,7 +1653,7 @@ cliui@^8.0.1: clone@2.x: version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz" integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== cluster-key-slot@^1.1.0: @@ -1612,51 +1663,51 @@ cluster-key-slot@^1.1.0: co@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== codepage@~1.15.0: version "1.15.0" - resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab" + resolved "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz" integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA== collect-v8-coverage@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== color-string@^1.6.0: version "1.9.1" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== dependencies: color-name "^1.0.0" @@ -1664,7 +1715,7 @@ color-string@^1.6.0: color@^3.1.3: version "3.2.1" - resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz" integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== dependencies: color-convert "^1.9.3" @@ -1672,7 +1723,7 @@ color@^3.1.3: colorspace@1.1.x: version "1.1.4" - resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz" integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== dependencies: color "^3.1.3" @@ -1680,14 +1731,14 @@ colorspace@1.1.x: combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" compress-commons@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.2.tgz#6542e59cb63e1f46a8b21b0e06f9a32e4c8b06df" + resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz" integrity sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg== dependencies: buffer-crc32 "^0.2.13" @@ -1697,14 +1748,14 @@ compress-commons@^4.1.2: compressible@~2.0.16: version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz" integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== dependencies: mime-db ">= 1.43.0 < 2" compression@1.7.4: version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + resolved "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz" integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== dependencies: accepts "~1.3.5" @@ -1717,54 +1768,54 @@ compression@1.7.4: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== content-disposition@0.5.4: version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== dependencies: safe-buffer "5.2.1" content-type@~1.0.4, content-type@~1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== convert-source-map@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== cookie@0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== core-util-is@~1.0.0: version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== crc-32@^1.2.0, crc-32@~1.2.0, crc-32@~1.2.1: version "1.2.2" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== crc32-stream@^4.0.2: version "4.0.3" - resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.3.tgz#85dd677eb78fa7cad1ba17cc506a597d41fc6f33" + resolved "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz" integrity sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw== dependencies: crc-32 "^1.2.0" @@ -1772,7 +1823,7 @@ crc32-stream@^4.0.2: create-jest@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + resolved "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz" integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== dependencies: "@jest/types" "^29.6.3" @@ -1785,12 +1836,12 @@ create-jest@^29.7.0: create-require@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" @@ -1798,54 +1849,61 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: which "^2.0.1" dayjs@^1.8.34: - version "1.11.13" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" - integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + version "1.11.11" + resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz" + integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== debug@2.6.9, debug@^2.1.3: version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4, debug@^4.3.6: - version "4.3.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" - integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.3.1, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: - ms "^2.1.3" + ms "2.1.2" + +debug@^4.1.1: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" decompress-response@^3.3.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz" integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== dependencies: mimic-response "^1.0.0" dedent@^1.0.0: - version "1.5.3" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" - integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== + version "1.5.1" + resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== deep-extend@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: version "4.3.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== define-data-property@^1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: es-define-property "^1.0.0" @@ -1854,17 +1912,17 @@ define-data-property@^1.1.4: delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== delegates@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== denque@^1.3.0: version "1.5.1" - resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + resolved "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz" integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== denque@^2.1.0: @@ -1874,117 +1932,112 @@ denque@^2.1.0: depd@2.0.0, depd@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== destroy@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== detect-libc@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz" integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== detect-newline@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== diff-sequences@^29.6.3: version "29.6.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz" integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== diff@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== doctrine@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== dependencies: esutils "^2.0.2" duplexer2@~0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + resolved "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz" integrity sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA== dependencies: readable-stream "^2.0.2" dynamic-dedupe@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz#06e44c223f5e4e94d78ef9db23a6515ce2f962a1" + resolved "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz" integrity sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ== dependencies: xtend "^4.0.0" eastasianwidth@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== ee-first@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.5.4: - version "1.5.27" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz#5203ce5d6054857d84ba84d3681cbe59132ade78" - integrity sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw== +electron-to-chromium@^1.4.668: + version "1.4.806" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz#2cb046631cbabceb26fc72be68d273fa183e36bc" + integrity sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg== emittery@^0.13.1: version "0.13.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== emoji-regex@^9.2.2: version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== enabled@2.0.x: version "2.0.0" - resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== encodeurl@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -encodeurl@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" - integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== - encoding@^0.1.13: version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== dependencies: iconv-lite "^0.6.2" end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" enquirer@^2.3.5: version "2.4.1" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz" integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== dependencies: ansi-colors "^4.1.1" @@ -1992,71 +2045,64 @@ enquirer@^2.3.5: env-paths@^2.2.0: version "2.2.1" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== err-code@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== error-ex@^1.3.1: version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -error@7.0.2: +error@7.0.2, error@^7.0.0: version "7.0.2" - resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz" integrity sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw== dependencies: string-template "~0.2.1" xtend "~4.0.0" -error@^7.0.0: - version "7.2.1" - resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894" - integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA== - dependencies: - string-template "~0.2.1" - es-define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz" integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== dependencies: get-intrinsic "^1.2.4" es-errors@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -escalade@^3.1.1, escalade@^3.1.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== +escalade@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== escodegen@^1.8.1: version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== dependencies: esprima "^4.0.1" @@ -2068,7 +2114,7 @@ escodegen@^1.8.1: eslint-scope@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: esrecurse "^4.3.0" @@ -2076,24 +2122,24 @@ eslint-scope@^5.1.1: eslint-utils@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== eslint-visitor-keys@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== eslint@7.16.0: version "7.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.16.0.tgz#a761605bf9a7b32d24bb7cde59aeb0fd76f06092" + resolved "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz" integrity sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw== dependencies: "@babel/code-frame" "^7.0.0" @@ -2136,7 +2182,7 @@ eslint@7.16.0: espree@^7.3.0, espree@^7.3.1: version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz" integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== dependencies: acorn "^7.4.0" @@ -2145,56 +2191,56 @@ espree@^7.3.0, espree@^7.3.1: esprima@1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.2.tgz#76a0fd66fcfe154fd292667dc264019750b1657b" + resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz" integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A== esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.2.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" - integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + version "1.5.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== dependencies: estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: estraverse "^5.2.0" estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== etag@~1.8.1: version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== eventemitter3@^4.0.0: version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -exceljs@^4.4.0: +exceljs@4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/exceljs/-/exceljs-4.4.0.tgz#cfb1cb8dcc82c760a9fc9faa9e52dadab66b0156" + resolved "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz" integrity sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg== dependencies: archiver "^5.0.0" @@ -2209,7 +2255,7 @@ exceljs@^4.4.0: execa@^5.0.0: version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" @@ -2224,17 +2270,17 @@ execa@^5.0.0: exit@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== expand-template@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + resolved "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== expect@^29.0.0, expect@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + resolved "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz" integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== dependencies: "@jest/expect-utils" "^29.7.0" @@ -2245,40 +2291,40 @@ expect@^29.0.0, expect@^29.7.0: exponential-backoff@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" + resolved "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz" integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== express@^4.19.2: - version "4.21.0" - resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" - integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== + version "4.19.2" + resolved "https://registry.npmjs.org/express/-/express-4.19.2.tgz" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.3" + body-parser "1.20.2" content-disposition "0.5.4" content-type "~1.0.4" cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~2.0.0" + encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.3.1" + finalhandler "1.2.0" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.3" + merge-descriptors "1.0.1" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.10" + path-to-regexp "0.1.7" proxy-addr "~2.0.7" - qs "6.13.0" + qs "6.11.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.19.0" - serve-static "1.16.2" + send "0.18.0" + serve-static "1.15.0" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -2287,7 +2333,7 @@ express@^4.19.2: fast-csv@^4.3.1: version "4.3.6" - resolved "https://registry.yarnpkg.com/fast-csv/-/fast-csv-4.3.6.tgz#70349bdd8fe4d66b1130d8c91820b64a21bc4a63" + resolved "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz" integrity sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw== dependencies: "@fast-csv/format" "4.3.5" @@ -2295,62 +2341,57 @@ fast-csv@^4.3.1: fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fast-uri@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" - integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== - fb-watchman@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== dependencies: bser "2.1.1" fecha@^4.2.0: version "4.2.3" - resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz" integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== file-entry-cache@^6.0.0: version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: flat-cache "^3.0.4" file-uri-to-path@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" -finalhandler@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" - integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== dependencies: debug "2.6.9" - encodeurl "~2.0.0" + encodeurl "~1.0.2" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -2359,7 +2400,7 @@ finalhandler@1.3.1: find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: locate-path "^5.0.0" @@ -2367,7 +2408,7 @@ find-up@^4.0.0, find-up@^4.1.0: flat-cache@^3.0.4: version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: flatted "^3.2.9" @@ -2376,30 +2417,30 @@ flat-cache@^3.0.4: flatted@^3.2.9: version "3.3.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== fn.name@1.x.x: version "1.1.0" - resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== follow-redirects@^1.0.0, follow-redirects@^1.15.6: - version "1.15.9" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" - integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + version "1.15.6" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== foreground-child@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" - integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + version "3.1.1" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" form-data@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" @@ -2408,41 +2449,41 @@ form-data@^4.0.0: forwarded@0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== frac@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b" + resolved "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz" integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA== fresh@0.5.2: version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== fs-constants@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== fs-minipass@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== dependencies: minipass "^3.0.0" fs-minipass@^3.0.0: version "3.0.3" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-3.0.3.tgz#79a85981c4dc120065e96f62086bf6f9dc26cc54" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz" integrity sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw== dependencies: minipass "^7.0.3" fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.3.2, fsevents@~2.3.2: @@ -2452,7 +2493,7 @@ fsevents@^2.3.2, fsevents@~2.3.2: fstream@^1.0.12: version "1.0.12" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz" integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== dependencies: graceful-fs "^4.1.2" @@ -2462,17 +2503,17 @@ fstream@^1.0.12: function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== functional-red-black-tree@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== gauge@~2.7.3: version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz" integrity sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg== dependencies: aproba "^1.0.3" @@ -2486,17 +2527,17 @@ gauge@~2.7.3: gensync@^1.0.0-beta.2: version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: es-errors "^1.3.0" @@ -2507,41 +2548,40 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: get-package-type@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== get-stream@^6.0.0: version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== github-from-package@0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== glob-parent@^5.0.0, glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" glob@^10.2.2, glob@^10.3.10: - version "10.4.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + version "10.3.12" + resolved "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== dependencies: foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.10.2" glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -2553,80 +2593,80 @@ glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: globals@^11.1.0: version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^12.1.0: version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz" integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== dependencies: type-fest "^0.8.1" gopd@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== dependencies: get-intrinsic "^1.1.3" graceful-fs@^4.1.2, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-property-descriptors@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: es-define-property "^1.0.0" has-proto@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz" integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== has-symbols@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== has-unicode@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== hash-sum@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a" + resolved "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz" integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg== -hasown@^2.0.0, hasown@^2.0.2: +hasown@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" helmet@7.1.0: version "7.1.0" - resolved "https://registry.yarnpkg.com/helmet/-/helmet-7.1.0.tgz#287279e00f8a3763d5dccbaf1e5ee39b8c3784ca" + resolved "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz" integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== hexer@^1.5.0: version "1.5.0" - resolved "https://registry.yarnpkg.com/hexer/-/hexer-1.5.0.tgz#b86ce808598e8a9d1892c571f3cedd86fc9f0653" + resolved "https://registry.npmjs.org/hexer/-/hexer-1.5.0.tgz" integrity sha512-dyrPC8KzBzUJ19QTIo1gXNqIISRXQ0NwteW6OeQHRN4ZuZeHkdODfj0zHBdOlHbRY8GqbqK57C9oWSvQZizFsg== dependencies: ansi-color "^0.2.1" @@ -2636,17 +2676,17 @@ hexer@^1.5.0: html-escaper@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== http-cache-semantics@^4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== http-errors@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: depd "2.0.0" @@ -2657,27 +2697,27 @@ http-errors@2.0.0: http-proxy-agent@^7.0.0: version "7.0.2" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz" integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== dependencies: agent-base "^7.1.0" debug "^4.3.4" http-proxy-middleware@*, http-proxy-middleware@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-3.0.2.tgz#c834aad7cac47a229205399ab64a102e9bbed820" - integrity sha512-fBLFpmvDzlxdckwZRjM0wWtwDZ4KBtQ8NFqhrFKoEtK4myzuiumBuNTxD+F4cVbXfOZljIbrynmvByofDzT7Ag== + version "3.0.0" + resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz" + integrity sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw== dependencies: - "@types/http-proxy" "^1.17.15" - debug "^4.3.6" + "@types/http-proxy" "^1.17.10" + debug "^4.3.4" http-proxy "^1.18.1" - is-glob "^4.0.3" - is-plain-object "^5.0.0" - micromatch "^4.0.8" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.5" http-proxy@^1.18.1: version "1.18.1" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz" integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== dependencies: eventemitter3 "^4.0.0" @@ -2685,76 +2725,76 @@ http-proxy@^1.18.1: requires-port "^1.0.0" https-proxy-agent@^7.0.1: - version "7.0.5" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" - integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== + version "7.0.4" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz" + integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg== dependencies: agent-base "^7.0.2" debug "4" human-signals@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== iconv-lite@0.4.24: version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" iconv-lite@^0.6.2: version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" ieee754@^1.1.13: version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore@^4.0.6: version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== immediate@~3.0.5: version "3.0.6" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" import-local@^3.0.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" - integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + version "3.1.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== indent-string@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" @@ -2762,12 +2802,12 @@ inflight@^1.0.4: inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== ini@~1.3.0: version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== ioredis@^5.4.1: @@ -2787,7 +2827,7 @@ ioredis@^5.4.1: ip-address@^9.0.5: version "9.0.5" - resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" + resolved "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz" integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== dependencies: jsbn "1.1.0" @@ -2795,105 +2835,105 @@ ip-address@^9.0.5: ipaddr.js@1.9.1: version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-arrayish@^0.3.1: version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" is-core-module@^2.13.0: - version "2.15.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" - integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + version "2.13.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: - hasown "^2.0.2" + hasown "^2.0.0" is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-generator-fn@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" is-lambda@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== is-number@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== is-stream@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== isarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isexe@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" + resolved "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz" integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz" integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== istanbul-lib-instrument@^5.0.4: version "5.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== dependencies: "@babel/core" "^7.12.3" @@ -2903,9 +2943,9 @@ istanbul-lib-instrument@^5.0.4: semver "^6.3.0" istanbul-lib-instrument@^6.0.0: - version "6.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" - integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + version "6.0.2" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz" + integrity sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw== dependencies: "@babel/core" "^7.23.9" "@babel/parser" "^7.23.9" @@ -2915,7 +2955,7 @@ istanbul-lib-instrument@^6.0.0: istanbul-lib-report@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: istanbul-lib-coverage "^3.0.0" @@ -2924,7 +2964,7 @@ istanbul-lib-report@^3.0.0: istanbul-lib-source-maps@^4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" @@ -2933,16 +2973,16 @@ istanbul-lib-source-maps@^4.0.0: istanbul-reports@^3.1.3: version "3.1.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz" integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jackspeak@^3.1.2: - version "3.4.3" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" - integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== +jackspeak@^2.3.6: + version "2.3.6" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -2950,7 +2990,7 @@ jackspeak@^3.1.2: jaeger-client@^3.19.0: version "3.19.0" - resolved "https://registry.yarnpkg.com/jaeger-client/-/jaeger-client-3.19.0.tgz#9b5bd818ebd24e818616ee0f5cffe1722a53ae6e" + resolved "https://registry.npmjs.org/jaeger-client/-/jaeger-client-3.19.0.tgz" integrity sha512-M0c7cKHmdyEUtjemnJyx/y9uX16XHocL46yQvyqDlPdvAcwPDbHrIbKjQdBqtiE4apQ/9dmr+ZLJYYPGnurgpw== dependencies: node-int64 "^0.4.0" @@ -2961,7 +3001,7 @@ jaeger-client@^3.19.0: jest-changed-files@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz" integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: execa "^5.0.0" @@ -2970,7 +3010,7 @@ jest-changed-files@^29.7.0: jest-circus@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz" integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== dependencies: "@jest/environment" "^29.7.0" @@ -2996,7 +3036,7 @@ jest-circus@^29.7.0: jest-cli@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz" integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: "@jest/core" "^29.7.0" @@ -3013,7 +3053,7 @@ jest-cli@^29.7.0: jest-config@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz" integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== dependencies: "@babel/core" "^7.11.6" @@ -3041,7 +3081,7 @@ jest-config@^29.7.0: jest-diff@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz" integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== dependencies: chalk "^4.0.0" @@ -3051,14 +3091,14 @@ jest-diff@^29.7.0: jest-docblock@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz" integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== dependencies: detect-newline "^3.0.0" jest-each@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz" integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: "@jest/types" "^29.6.3" @@ -3069,7 +3109,7 @@ jest-each@^29.7.0: jest-environment-node@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz" integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== dependencies: "@jest/environment" "^29.7.0" @@ -3081,12 +3121,12 @@ jest-environment-node@^29.7.0: jest-get-type@^29.6.3: version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz" integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== jest-haste-map@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz" integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: "@jest/types" "^29.6.3" @@ -3105,7 +3145,7 @@ jest-haste-map@^29.7.0: jest-leak-detector@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz" integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: jest-get-type "^29.6.3" @@ -3113,7 +3153,7 @@ jest-leak-detector@^29.7.0: jest-matcher-utils@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz" integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== dependencies: chalk "^4.0.0" @@ -3123,7 +3163,7 @@ jest-matcher-utils@^29.7.0: jest-message-util@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz" integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== dependencies: "@babel/code-frame" "^7.12.13" @@ -3138,7 +3178,7 @@ jest-message-util@^29.7.0: jest-mock@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz" integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== dependencies: "@jest/types" "^29.6.3" @@ -3147,17 +3187,17 @@ jest-mock@^29.7.0: jest-pnp-resolver@^1.2.2: version "1.2.3" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== jest-regex-util@^29.6.3: version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz" integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== jest-resolve-dependencies@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz" integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: jest-regex-util "^29.6.3" @@ -3165,7 +3205,7 @@ jest-resolve-dependencies@^29.7.0: jest-resolve@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: chalk "^4.0.0" @@ -3180,7 +3220,7 @@ jest-resolve@^29.7.0: jest-runner@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz" integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== dependencies: "@jest/console" "^29.7.0" @@ -3207,7 +3247,7 @@ jest-runner@^29.7.0: jest-runtime@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz" integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== dependencies: "@jest/environment" "^29.7.0" @@ -3235,7 +3275,7 @@ jest-runtime@^29.7.0: jest-snapshot@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz" integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: "@babel/core" "^7.11.6" @@ -3261,7 +3301,7 @@ jest-snapshot@^29.7.0: jest-util@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: "@jest/types" "^29.6.3" @@ -3273,7 +3313,7 @@ jest-util@^29.7.0: jest-validate@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz" integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== dependencies: "@jest/types" "^29.6.3" @@ -3285,7 +3325,7 @@ jest-validate@^29.7.0: jest-watcher@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz" integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: "@jest/test-result" "^29.7.0" @@ -3299,7 +3339,7 @@ jest-watcher@^29.7.0: jest-worker@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz" integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: "@types/node" "*" @@ -3309,7 +3349,7 @@ jest-worker@^29.7.0: jest@29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: "@jest/core" "^29.7.0" @@ -3319,12 +3359,12 @@ jest@29.7.0: js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" @@ -3332,47 +3372,47 @@ js-yaml@^3.13.1: jsbn@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz" integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== json-buffer@3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== json-parse-even-better-errors@^2.3.0: version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema-traverse@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== json5@^2.2.3: version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== jsonpath@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/jsonpath/-/jsonpath-1.1.1.tgz#0ca1ed8fb65bb3309248cc9d5466d12d5b0b9901" + resolved "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz" integrity sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w== dependencies: esprima "1.2.2" @@ -3381,7 +3421,7 @@ jsonpath@1.1.1: jszip@^3.10.1, jszip@^3.2.2: version "3.10.1" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" + resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz" integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== dependencies: lie "~3.3.0" @@ -3391,7 +3431,7 @@ jszip@^3.10.1, jszip@^3.2.2: kafka-node@5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/kafka-node/-/kafka-node-5.0.0.tgz#4b6f65cc1d77ebe565859dfb8f9575ed15d543c0" + resolved "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz" integrity sha512-dD2ga5gLcQhsq1yNoQdy1MU4x4z7YnXM5bcG9SdQuiNr5KKuAmXixH1Mggwdah5o7EfholFbcNDPSVA6BIfaug== dependencies: async "^2.6.2" @@ -3412,36 +3452,36 @@ kafka-node@5.0.0: keyv@^4.5.3: version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" kleur@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== kuler@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz" integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== lazystream@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + resolved "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz" integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== dependencies: readable-stream "^2.0.5" leven@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== levn@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" @@ -3449,7 +3489,7 @@ levn@^0.4.1: levn@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== dependencies: prelude-ls "~1.1.2" @@ -3457,51 +3497,51 @@ levn@~0.3.0: lie@~3.3.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz" integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== dependencies: immediate "~3.0.5" lines-and-columns@^1.1.6: version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== listenercount@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" + resolved "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz" integrity sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ== locate-path@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: p-locate "^4.1.0" lodash.defaults@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz" integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== lodash.difference@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + resolved "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz" integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== lodash.escaperegexp@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" + resolved "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz" integrity sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw== lodash.flatten@^4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz" integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== lodash.groupby@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" + resolved "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz" integrity sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw== lodash.isarguments@^3.1.0: @@ -3511,58 +3551,58 @@ lodash.isarguments@^3.1.0: lodash.isboolean@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + resolved "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz" integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== lodash.isequal@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== lodash.isfunction@^3.0.9: version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" + resolved "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz" integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== lodash.isnil@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz#49e28cd559013458c814c5479d3c663a21bfaa6c" + resolved "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz" integrity sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng== lodash.isplainobject@^4.0.6: version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== lodash.isundefined@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz#23ef3d9535565203a66cefd5b830f848911afb48" + resolved "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz" integrity sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA== lodash.truncate@^4.4.2: version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== lodash.union@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz" integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== lodash.uniq@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== lodash@4.17.21, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4: version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -logform@^2.4.0, logform@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.1.tgz#71403a7d8cae04b2b734147963236205db9b3df0" - integrity sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA== +logform@^2.3.2, logform@^2.4.0: + version "2.6.0" + resolved "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz" + integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ== dependencies: "@colors/colors" "1.6.0" "@types/triple-beam" "^1.3.2" @@ -3573,42 +3613,49 @@ logform@^2.4.0, logform@^2.6.1: long@1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/long/-/long-1.1.2.tgz#eaef5951ca7551d96926b82da242db9d6b28fb53" + resolved "https://registry.npmjs.org/long/-/long-1.1.2.tgz" integrity sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q== long@^2.4.0: version "2.4.0" - resolved "https://registry.yarnpkg.com/long/-/long-2.4.0.tgz#9fa180bb1d9500cdc29c4156766a1995e1f4524f" + resolved "https://registry.npmjs.org/long/-/long-2.4.0.tgz" integrity sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ== lru-cache@^10.0.1, lru-cache@^10.2.0: - version "10.4.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" - integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + version "10.2.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz" + integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== lru-cache@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: yallist "^3.0.2" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + make-dir@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== dependencies: semver "^7.5.3" make-error@^1.1.1: version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== make-fetch-happen@^13.0.0: - version "13.0.1" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz#273ba2f78f45e1f3a6dca91cede87d9fa4821e36" - integrity sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA== + version "13.0.0" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz" + integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A== dependencies: "@npmcli/agent" "^2.0.0" cacache "^18.0.0" @@ -3619,114 +3666,108 @@ make-fetch-happen@^13.0.0: minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" negotiator "^0.6.3" - proc-log "^4.2.0" promise-retry "^2.0.1" ssri "^10.0.0" makeerror@1.0.12: version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: tmpl "1.0.5" media-typer@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== -merge-descriptors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" - integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== methods@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^4.0.4, micromatch@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== +micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - braces "^3.0.3" + braces "^3.0.2" picomatch "^2.3.1" -mime-db@1.52.0: +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -"mime-db@>= 1.43.0 < 2": - version "1.53.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" - integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== - mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" mime@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== mimic-response@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" minimatch@^5.1.0: version "5.1.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== +minimatch@^9.0.1: + version "9.0.4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== dependencies: brace-expansion "^2.0.1" minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.6: version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minipass-collect@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-2.0.1.tgz#1621bc77e12258a12c60d34e2276ec5c20680863" + resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz" integrity sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw== dependencies: minipass "^7.0.3" minipass-fetch@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-3.0.5.tgz#f0f97e40580affc4a35cc4a1349f05ae36cb1e4c" - integrity sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg== + version "3.0.4" + resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz" + integrity sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg== dependencies: minipass "^7.0.3" minipass-sized "^1.0.3" @@ -3736,45 +3777,45 @@ minipass-fetch@^3.0.0: minipass-flush@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz" integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== dependencies: minipass "^3.0.0" minipass-pipeline@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz" integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== dependencies: minipass "^3.0.0" minipass-sized@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz" integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== dependencies: minipass "^3.0.0" minipass@^3.0.0: version "3.3.6" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz" integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== dependencies: yallist "^4.0.0" minipass@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4: + version "7.0.4" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== dependencies: minipass "^3.0.0" @@ -3782,19 +3823,19 @@ minizlib@^2.1.1, minizlib@^2.1.2: "mkdirp@>=0.5 0", mkdirp@^0.5.1: version "0.5.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: minimist "^1.2.6" mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== morgan@1.10.0: version "1.10.0" - resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" + resolved "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz" integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== dependencies: basic-auth "~2.0.1" @@ -3805,56 +3846,61 @@ morgan@1.10.0: ms@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.3, ms@^2.1.1, ms@^2.1.3: +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.1.1: version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== nan@^2.14.1: - version "2.20.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" - integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== + version "2.19.0" + resolved "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz" + integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== napi-build-utils@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz" integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== negotiator@0.6.3, negotiator@^0.6.3: version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== nested-error-stacks@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" + resolved "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz" integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== node-abi@^2.7.0: version "2.30.1" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.30.1.tgz#c437d4b1fe0e285aaf290d45b45d4d7afedac4cf" + resolved "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz" integrity sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w== dependencies: semver "^5.4.1" node-cache@5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d" + resolved "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz" integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== dependencies: clone "2.x" node-gyp@10.0.1: version "10.0.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.0.1.tgz#205514fc19e5830fa991e4a689f9e81af377a966" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz" integrity sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg== dependencies: env-paths "^2.2.0" @@ -3870,41 +3916,41 @@ node-gyp@10.0.1: node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.18: - version "2.0.18" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" - integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== noop-logger@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" + resolved "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz" integrity sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ== nopt@^7.0.0: - version "7.2.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.1.tgz#1cac0eab9b8e97c9093338446eddd40b2c8ca1e7" - integrity sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w== + version "7.2.0" + resolved "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz" + integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== dependencies: abbrev "^2.0.0" normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== npm-run-path@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" npmlog@^4.0.1: version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" @@ -3914,77 +3960,77 @@ npmlog@^4.0.1: number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== object-assign@^4.1.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-inspect@^1.13.1: - version "1.13.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" - integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + version "1.13.1" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== obuf@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== on-finished@2.4.1: version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== dependencies: ee-first "1.1.1" on-finished@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== dependencies: ee-first "1.1.1" on-headers@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" one-time@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + resolved "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz" integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== dependencies: fn.name "1.x.x" onetime@^5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" opentracing@^0.14.4, opentracing@^0.14.7, opentracing@~0.14.3: version "0.14.7" - resolved "https://registry.yarnpkg.com/opentracing/-/opentracing-0.14.7.tgz#25d472bd0296dc0b64d7b94cbc995219031428f5" + resolved "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz" integrity sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q== optional@^0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/optional/-/optional-0.1.4.tgz#cdb1a9bedc737d2025f690ceeb50e049444fd5b3" + resolved "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz" integrity sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw== optionator@^0.8.1: version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" @@ -3995,75 +4041,70 @@ optionator@^0.8.1: word-wrap "~1.2.3" optionator@^0.9.1: - version "0.9.4" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" - integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + version "0.9.3" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.5" os-homedir@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== p-limit@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" p-limit@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" p-locate@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== dependencies: p-limit "^2.2.0" p-map@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== dependencies: aggregate-error "^3.0.0" p-try@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -package-json-from-dist@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" - integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== - pako@~1.0.2: version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== parent-module@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" parse-json@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" @@ -4073,75 +4114,75 @@ parse-json@^5.2.0: parseurl@~1.3.3: version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== +path-scurry@^1.10.2: + version "1.10.2" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz" + integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== dependencies: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" - integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== pg-cloudflare@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98" + resolved "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz" integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== pg-connection-string@^2.6.4: - version "2.7.0" - resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.7.0.tgz#f1d3489e427c62ece022dba98d5262efcb168b37" - integrity sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA== + version "2.6.4" + resolved "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz" + integrity sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA== pg-int8@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + resolved "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz" integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== pg-numeric@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a" + resolved "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz" integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== pg-pool@^3.6.2: - version "3.7.0" - resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.7.0.tgz#d4d3c7ad640f8c6a2245adc369bafde4ebb8cbec" - integrity sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g== + version "3.6.2" + resolved "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz" + integrity sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg== pg-protocol@*, pg-protocol@^1.6.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.7.0.tgz#ec037c87c20515372692edac8b63cf4405448a93" - integrity sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ== + version "1.6.1" + resolved "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz" + integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg== pg-types@^2.1.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + resolved "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz" integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== dependencies: pg-int8 "1.0.1" @@ -4152,7 +4193,7 @@ pg-types@^2.1.0: pg-types@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-4.0.2.tgz#399209a57c326f162461faa870145bb0f918b76d" + resolved "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz" integrity sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng== dependencies: pg-int8 "1.0.1" @@ -4165,7 +4206,7 @@ pg-types@^4.0.1: pg@8.12.0: version "8.12.0" - resolved "https://registry.yarnpkg.com/pg/-/pg-8.12.0.tgz#9341724db571022490b657908f65aee8db91df79" + resolved "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz" integrity sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ== dependencies: pg-connection-string "^2.6.4" @@ -4178,85 +4219,85 @@ pg@8.12.0: pgpass@1.x: version "1.0.5" - resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" + resolved "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz" integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== dependencies: split2 "^4.1.0" -picocolors@^1.0.0, picocolors@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" - integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pirates@^4.0.4: version "4.0.6" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== pkg-dir@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" postgres-array@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz" integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== postgres-array@~3.0.1: version "3.0.2" - resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-3.0.2.tgz#68d6182cb0f7f152a7e60dc6a6889ed74b0a5f98" + resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz" integrity sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog== postgres-bytea@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz" integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== postgres-bytea@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-3.0.0.tgz#9048dc461ac7ba70a6a42d109221619ecd1cb089" + resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz" integrity sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw== dependencies: obuf "~1.1.2" postgres-date@~1.0.4: version "1.0.7" - resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz" integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== postgres-date@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-2.1.0.tgz#b85d3c1fb6fb3c6c8db1e9942a13a3bf625189d0" + resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz" integrity sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA== postgres-interval@^1.1.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz" integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== dependencies: xtend "^4.0.0" postgres-interval@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-3.0.0.tgz#baf7a8b3ebab19b7f38f07566c7aab0962f0c86a" + resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz" integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw== postgres-range@^1.1.1: version "1.1.4" - resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863" + resolved "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz" integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== prebuild-install@5.3.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.0.tgz#58b4d8344e03590990931ee088dd5401b03004c8" + resolved "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz" integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg== dependencies: detect-libc "^1.0.3" @@ -4278,17 +4319,17 @@ prebuild-install@5.3.0: prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz" integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== dependencies: "@jest/schemas" "^29.6.3" @@ -4297,39 +4338,34 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: proc-log@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" + resolved "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz" integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== -proc-log@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-4.2.0.tgz#b6f461e4026e75fdfe228b265e9f7a00779d7034" - integrity sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA== - process-nextick-args@~2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== process@^0.10.0: version "0.10.1" - resolved "https://registry.yarnpkg.com/process/-/process-0.10.1.tgz#842457cc51cfed72dc775afeeafb8c6034372725" + resolved "https://registry.npmjs.org/process/-/process-0.10.1.tgz" integrity sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA== progress@^2.0.0: version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== "prom-client@~11.3.0 || ^12.0.0 || ^13.0.0 || ^14.0.0": version "14.2.0" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.2.0.tgz#ca94504e64156f6506574c25fb1c34df7812cf11" + resolved "https://registry.npmjs.org/prom-client/-/prom-client-14.2.0.tgz" integrity sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA== dependencies: tdigest "^0.1.1" promise-retry@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz" integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== dependencies: err-code "^2.0.2" @@ -4337,7 +4373,7 @@ promise-retry@^2.0.1: prompts@^2.0.1: version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: kleur "^3.0.3" @@ -4345,12 +4381,12 @@ prompts@^2.0.1: property-expr@^2.0.5: version "2.0.6" - resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" + resolved "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz" integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== proxy-addr@~2.0.7: version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: forwarded "0.2.0" @@ -4358,12 +4394,12 @@ proxy-addr@~2.0.7: proxy-from-env@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== pump@^1.0.0: version "1.0.3" - resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + resolved "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz" integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== dependencies: end-of-stream "^1.1.0" @@ -4371,7 +4407,7 @@ pump@^1.0.0: pump@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz" integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== dependencies: end-of-stream "^1.1.0" @@ -4379,29 +4415,29 @@ pump@^2.0.1: punycode@^2.1.0: version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== pure-rand@^6.0.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz" integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== -qs@6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" - integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== +qs@6.11.0: + version "6.11.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: - side-channel "^1.0.6" + side-channel "^1.0.4" range-parser@~1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== raw-body@2.5.2: version "2.5.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz" integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" @@ -4411,7 +4447,7 @@ raw-body@2.5.2: rc@^1.2.7: version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" @@ -4420,13 +4456,13 @@ rc@^1.2.7: strip-json-comments "~2.0.1" react-is@^18.0.0: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" - integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + version "18.2.0" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: version "2.3.8" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" @@ -4437,9 +4473,9 @@ readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0, readable-stream@^3.6.2: +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" @@ -4448,14 +4484,14 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0, readable readdir-glob@^1.1.2: version "1.1.3" - resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584" + resolved "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz" integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== dependencies: minimatch "^5.1.0" readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" @@ -4474,49 +4510,49 @@ redis-parser@^3.0.0: regexpp@^3.1.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-from-string@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== requires-port@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== resolve-cwd@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== dependencies: resolve-from "^5.0.0" resolve-from@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve-from@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve.exports@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== resolve@^1.0.0, resolve@^1.20.0: version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" @@ -4525,79 +4561,81 @@ resolve@^1.0.0, resolve@^1.20.0: retry@^0.10.1: version "0.10.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + resolved "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz" integrity sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ== retry@^0.12.0: version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== rimraf@2, rimraf@^2.6.1: version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: glob "^7.1.3" rimraf@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.2.0: +safe-buffer@5.2.1: version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== safe-stable-stringify@^2.3.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" - integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== + version "2.4.3" + resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz" + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sax@^1.2.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" - integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== + version "1.3.0" + resolved "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz" + integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== saxes@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz" integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== dependencies: xmlchars "^2.2.0" semver@^5.4.1: version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== semver@^6.3.0, semver@^6.3.1: version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== semver@^7.2.1, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + version "7.6.0" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" -send@0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" - integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== +send@0.18.0: + version "0.18.0" + resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== dependencies: debug "2.6.9" depd "2.0.0" @@ -4613,24 +4651,24 @@ send@0.19.0: range-parser "~1.2.1" statuses "2.0.1" -serve-static@1.16.2: - version "1.16.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" - integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== dependencies: - encodeurl "~2.0.0" + encodeurl "~1.0.2" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.19.0" + send "0.18.0" set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== set-function-length@^1.2.1: version "1.2.2" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: define-data-property "^1.1.4" @@ -4642,29 +4680,29 @@ set-function-length@^1.2.1: setimmediate@^1.0.5, setimmediate@~1.0.4: version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== setprototypeof@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.6: +side-channel@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz" integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: call-bind "^1.0.7" @@ -4674,22 +4712,22 @@ side-channel@^1.0.6: signal-exit@^3.0.0, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== signal-exit@^4.0.1: version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== simple-concat@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== simple-get@^2.7.0: version "2.8.2" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.2.tgz#5708fb0919d440657326cd5fe7d2599d07705019" + resolved "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz" integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== dependencies: decompress-response "^3.3.0" @@ -4698,24 +4736,24 @@ simple-get@^2.7.0: simple-swizzle@^0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== dependencies: is-arrayish "^0.3.1" sisteransi@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== slash@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== slice-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== dependencies: ansi-styles "^4.0.0" @@ -4724,12 +4762,12 @@ slice-ansi@^4.0.0: smart-buffer@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== snappy@^6.0.1: version "6.3.5" - resolved "https://registry.yarnpkg.com/snappy/-/snappy-6.3.5.tgz#c14b8dea8e9bc2687875b5e491d15dd900e6023c" + resolved "https://registry.npmjs.org/snappy/-/snappy-6.3.5.tgz" integrity sha512-lonrUtdp1b1uDn1dbwgQbBsb5BbaiLeKq+AGwOk2No+en+VvJThwmtztwulEQsLinRF681pBqib0NUZaizKLIA== dependencies: bindings "^1.3.1" @@ -4737,80 +4775,72 @@ snappy@^6.0.1: prebuild-install "5.3.0" socks-proxy-agent@^8.0.3: - version "8.0.4" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz#9071dca17af95f483300316f4b063578fa0db08c" - integrity sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw== + version "8.0.3" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz" + integrity sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A== dependencies: agent-base "^7.1.1" debug "^4.3.4" - socks "^2.8.3" + socks "^2.7.1" -socks@^2.8.3: - version "2.8.3" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" - integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== +socks@^2.7.1: + version "2.8.1" + resolved "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz" + integrity sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ== dependencies: ip-address "^9.0.5" smart-buffer "^4.2.0" -source-map-support@0.5.13: +source-map-support@0.5.13, source-map-support@^0.5.12: version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.5.12: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== split2@^4.1.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== sprintf-js@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== ssf@~0.11.2: version "0.11.2" - resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c" + resolved "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz" integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g== dependencies: frac "~1.1.2" ssri@^10.0.0: - version "10.0.6" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.6.tgz#a8aade2de60ba2bce8688e3fa349bad05c7dc1e5" - integrity sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ== + version "10.0.5" + resolved "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz" + integrity sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A== dependencies: minipass "^7.0.3" stack-trace@0.0.x: version "0.0.10" - resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz" integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== stack-utils@^2.0.3: version "2.0.6" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== dependencies: escape-string-regexp "^2.0.0" @@ -4822,19 +4852,19 @@ standard-as-callback@^2.1.0: static-eval@2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42" + resolved "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz" integrity sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg== dependencies: escodegen "^1.8.1" statuses@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== string-length@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: char-regex "^1.0.2" @@ -4842,125 +4872,134 @@ string-length@^4.0.1: string-template@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz" integrity sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw== -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^1.0.1: +string-width@^1.0.1, "string-width@^1.0.2 || 2 || 3 || 4": version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: eastasianwidth "^0.2.0" emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: +string_decoder@^1.1.1, string_decoder@~1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== dependencies: ansi-regex "^2.0.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: ansi-regex "^6.0.1" strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-bom@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== strip-final-newline@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" supports-color@^8.0.0: version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== table@^6.0.4: version "6.8.2" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.2.tgz#c5504ccf201213fa227248bdc8c5569716ac6c58" + resolved "https://registry.npmjs.org/table/-/table-6.8.2.tgz" integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA== dependencies: ajv "^8.0.1" @@ -4971,7 +5010,7 @@ table@^6.0.4: tar-fs@^1.13.0: version "1.16.3" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz" integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== dependencies: chownr "^1.0.1" @@ -4981,7 +5020,7 @@ tar-fs@^1.13.0: tar-stream@^1.1.2: version "1.6.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz" integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== dependencies: bl "^1.0.0" @@ -4994,7 +5033,7 @@ tar-stream@^1.1.2: tar-stream@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== dependencies: bl "^4.0.3" @@ -5005,7 +5044,7 @@ tar-stream@^2.2.0: tar@^6.1.11, tar@^6.1.2: version "6.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz" integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== dependencies: chownr "^2.0.0" @@ -5017,14 +5056,14 @@ tar@^6.1.11, tar@^6.1.2: tdigest@^0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.2.tgz#96c64bac4ff10746b910b0e23b515794e12faced" + resolved "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz" integrity sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA== dependencies: bintrees "1.0.2" test-exclude@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" @@ -5033,17 +5072,17 @@ test-exclude@^6.0.0: text-hex@1.0.x: version "1.0.0" - resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== text-table@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== thriftrw@^3.5.0: version "3.11.4" - resolved "https://registry.yarnpkg.com/thriftrw/-/thriftrw-3.11.4.tgz#84c990ee89e926631c0b475909ada44ee9249870" + resolved "https://registry.npmjs.org/thriftrw/-/thriftrw-3.11.4.tgz" integrity sha512-UcuBd3eanB3T10nXWRRMwfwoaC6VMk7qe3/5YIWP2Jtw+EbHqJ0p1/K3x8ixiR5dozKSSfcg1W+0e33G1Di3XA== dependencies: bufrw "^1.2.1" @@ -5052,64 +5091,64 @@ thriftrw@^3.5.0: tiny-case@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" + resolved "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz" integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== tmp@^0.2.0: version "0.2.3" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz" integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== tmpl@1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-buffer@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz" integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" toidentifier@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== toposort@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" + resolved "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz" integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== "traverse@>=0.3.0 <0.4": version "0.3.9" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" + resolved "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz" integrity sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ== tree-kill@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== triple-beam@^1.3.0: version "1.4.1" - resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" + resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz" integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== ts-node-dev@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-2.0.0.tgz#bdd53e17ab3b5d822ef519928dc6b4a7e0f13065" + resolved "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz" integrity sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w== dependencies: chokidar "^3.5.1" @@ -5125,7 +5164,7 @@ ts-node-dev@2.0.0: ts-node@^10.4.0: version "10.9.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== dependencies: "@cspotcode/source-map-support" "^0.8.0" @@ -5144,7 +5183,7 @@ ts-node@^10.4.0: tsconfig@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" + resolved "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz" integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== dependencies: "@types/strip-bom" "^3.0.0" @@ -5154,48 +5193,48 @@ tsconfig@^7.0.0: tunnel-agent@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== dependencies: safe-buffer "^5.0.1" type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: prelude-ls "^1.2.1" type-check@~0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== dependencies: prelude-ls "~1.1.2" type-detect@4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== type-fest@^0.21.3: version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== type-fest@^0.8.1: version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== type-fest@^2.19.0: version "2.19.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== type-is@~1.6.18: version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: media-typer "0.3.0" @@ -5203,46 +5242,41 @@ type-is@~1.6.18: typescript@5.4.2: version "5.4.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz" integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== underscore@1.12.1: version "1.12.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz" integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== undici-types@~5.26.4: version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -undici-types@~6.19.2: - version "6.19.8" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" - integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== - unique-filename@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea" + resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz" integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g== dependencies: unique-slug "^4.0.0" unique-slug@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-4.0.0.tgz#6bae6bb16be91351badd24cdce741f892a6532e3" + resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz" integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ== dependencies: imurmurhash "^0.1.4" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unzipper@^0.10.11: version "0.10.14" - resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.14.tgz#d2b33c977714da0fbc0f82774ad35470a7c962b1" + resolved "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz" integrity sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g== dependencies: big-integer "^1.6.17" @@ -5256,60 +5290,60 @@ unzipper@^0.10.11: readable-stream "~2.3.6" setimmediate "~1.0.4" -update-browserslist-db@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" - integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== dependencies: - escalade "^3.1.2" - picocolors "^1.0.1" + escalade "^3.1.1" + picocolors "^1.0.0" -uri-js@^4.2.2: +uri-js@^4.2.2, uri-js@^4.4.1: version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== utils-merge@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== uuid@9.0.1: version "9.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== uuid@^3.0.0: version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== v8-compile-cache-lib@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== v8-compile-cache@^2.0.3: version "2.4.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" + resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz" integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== v8-to-istanbul@^9.0.1: - version "9.3.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" - integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + version "9.2.0" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" @@ -5317,54 +5351,54 @@ v8-to-istanbul@^9.0.1: vary@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== walker@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: makeerror "1.0.12" which-pm-runs@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.1.0.tgz#35ccf7b1a0fce87bd8b92a478c9d045785d3bf35" + resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz" integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== which@^2.0.1: version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" which@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" + resolved "https://registry.npmjs.org/which/-/which-4.0.0.tgz" integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== dependencies: isexe "^3.1.1" wide-align@^1.1.0: version "1.1.5" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== dependencies: string-width "^1.0.2 || 2 || 3 || 4" winston-transport@^4.7.0: - version "4.7.1" - resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.1.tgz#52ff1bcfe452ad89991a0aaff9c3b18e7f392569" - integrity sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA== + version "4.7.0" + resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz" + integrity sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg== dependencies: - logform "^2.6.1" - readable-stream "^3.6.2" + logform "^2.3.2" + readable-stream "^3.6.0" triple-beam "^1.3.0" winston@3.12.0: version "3.12.0" - resolved "https://registry.yarnpkg.com/winston/-/winston-3.12.0.tgz#a5d965a41d3dc31be5408f8c66e927958846c0d0" + resolved "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz" integrity sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w== dependencies: "@colors/colors" "^1.6.0" @@ -5381,22 +5415,31 @@ winston@3.12.0: wmf@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da" + resolved "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz" integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw== -word-wrap@^1.2.5, word-wrap@~1.2.3: +word-wrap@~1.2.3: version "1.2.5" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== word@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961" + resolved "https://registry.npmjs.org/word/-/word-0.3.0.tgz" integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -5405,7 +5448,7 @@ word@~0.3.0: wrap-ansi@^8.1.0: version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: ansi-styles "^6.1.0" @@ -5414,12 +5457,12 @@ wrap-ansi@^8.1.0: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^4.0.2: version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== dependencies: imurmurhash "^0.1.4" @@ -5427,7 +5470,7 @@ write-file-atomic@^4.0.2: xlsx-populate@1.21.0: version "1.21.0" - resolved "https://registry.yarnpkg.com/xlsx-populate/-/xlsx-populate-1.21.0.tgz#f6cd02401f4cd3d055e81f2b6983ddfeeb60ffe6" + resolved "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz" integrity sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw== dependencies: cfb "^1.1.3" @@ -5437,7 +5480,7 @@ xlsx-populate@1.21.0: xlsx@*, xlsx@0.18.5: version "0.18.5" - resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0" + resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz" integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ== dependencies: adler-32 "~1.3.0" @@ -5450,42 +5493,42 @@ xlsx@*, xlsx@0.18.5: xmlchars@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== xorshift@^1.1.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/xorshift/-/xorshift-1.2.0.tgz#30a4cdd8e9f8d09d959ed2a88c42a09c660e8148" + resolved "https://registry.npmjs.org/xorshift/-/xorshift-1.2.0.tgz" integrity sha512-iYgNnGyeeJ4t6U11NpA/QiKy+PXn5Aa3Azg5qkwIFz1tBLllQrjjsk9yzD7IAK0naNU4JxdeDgqW9ov4u/hc4g== xtend@^4.0.0, xtend@~4.0.0: version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== y18n@^5.0.5: version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== yallist@^3.0.2: version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yallist@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yargs-parser@^21.1.1: version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== yargs@^17.3.1: version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" @@ -5498,17 +5541,17 @@ yargs@^17.3.1: yn@3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== yup@1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/yup/-/yup-1.4.0.tgz#898dcd660f9fb97c41f181839d3d65c3ee15a43e" + resolved "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz" integrity sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg== dependencies: property-expr "^2.0.5" @@ -5518,7 +5561,7 @@ yup@1.4.0: zip-stream@^4.1.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.1.tgz#1337fe974dbaffd2fa9a1ba09662a66932bd7135" + resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz" integrity sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ== dependencies: archiver-utils "^3.0.4" diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 95369041416..7865206457c 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -13,7 +13,6 @@ All notable changes to this module will be documented in this file. - Upgraded PostgresSQL Driver version to 42.7.1 - Upgraded Flyway base image version to 10.7.1 for DB Migration - Upgraded Flyway-Core to 9.22.3 -- Added `ExistentEntityValidator` fixes ## 1.1.2 - 2024-02-26 - Implemented validation for updating project start date and end date. diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 9cb321d57d0..fd0b688dcc3 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.20-dev-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common health-services-models - 1.0.23-dev-SNAPSHOT + 1.0.21-SNAPSHOT compile diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java index 219a38458ec..d602f809b15 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java @@ -1,13 +1,9 @@ package org.egov.project.repository; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.builder.SelectQueryBuilder; -import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; import org.egov.common.models.project.ProjectFacility; -import org.egov.common.models.project.ProjectFacilitySearch; import org.egov.common.producer.Producer; import org.egov.project.repository.rowmapper.ProjectFacilityRowMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -15,16 +11,15 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; -import java.util.List; import java.util.Optional; @Repository @Slf4j public class ProjectFacilityRepository extends GenericRepository { @Autowired public ProjectFacilityRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, - RedisTemplate redisTemplate, - SelectQueryBuilder selectQueryBuilder, ProjectFacilityRowMapper projectFacilityRowMapper) { + RedisTemplate redisTemplate, + SelectQueryBuilder selectQueryBuilder, ProjectFacilityRowMapper projectFacilityRowMapper) { super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, projectFacilityRowMapper, Optional.of("project_facility")); } -} \ No newline at end of file +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java index b2fcfb5672a..b9d3f814d7c 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.project.Document; import org.egov.tracer.model.CustomException; import org.postgresql.util.PGobject; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java index a5a8da51b09..b9ea8babec8 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.UserActionEnum; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java index b4cd46201b3..fa5d72c5dc7 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.project.Address; import org.egov.common.models.project.AddressType; import org.egov.common.models.project.Project; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java index 663ada6310f..c79c91ed161 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectBeneficiary; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java index 3d622db4a42..d6433f36db6 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectFacility; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java index bd6aa793bb6..34deb79333a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java @@ -1,7 +1,7 @@ package org.egov.project.repository.rowmapper; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.project.ProjectProductVariant; import org.egov.common.models.project.ProjectResource; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java index a4e1193eed2..b8625274dfc 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java @@ -1,6 +1,6 @@ package org.egov.project.repository.rowmapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.project.Project; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java index 169bdc99d40..a0ff3d24bcf 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectStaff; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index 406a7419c54..ccff648bd41 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.Address; import org.egov.common.models.project.AddressType; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java index 59477283fec..f9b352a69b4 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java @@ -1,6 +1,6 @@ package org.egov.project.repository.rowmapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.project.Target; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.ResultSetExtractor; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java index 1187e1692e6..87cab062d9c 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.TaskResource; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java index 57c992ae154..8a63f0f3c99 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.UserActionEnum; diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java index 9e5e47675bb..f7628318789 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java @@ -1,16 +1,9 @@ package org.egov.project.service; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectFacility; import org.egov.common.models.project.ProjectFacilityBulkRequest; import org.egov.common.models.project.ProjectFacilityRequest; @@ -34,6 +27,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import static org.egov.common.utils.CommonUtils.handleErrors; import static org.egov.common.utils.CommonUtils.havingTenantId; import static org.egov.common.utils.CommonUtils.includeDeleted; @@ -215,27 +214,27 @@ private Tuple, Map> validat return new Tuple<>(validEntities, errorDetailsMap); } - public SearchResponse search(ProjectFacilitySearchRequest projectFacilitySearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public List search(ProjectFacilitySearchRequest projectFacilitySearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("received request to search project facility"); if (isSearchByIdOnly(projectFacilitySearchRequest.getProjectFacility())) { log.info("searching project facility by id"); List ids = projectFacilitySearchRequest.getProjectFacility().getId(); log.info("fetching project facility with ids: {}", ids); - List projectfacilities = projectFacilityRepository.findById(ids, includeDeleted).stream() + return projectFacilityRepository.findById(ids, includeDeleted).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); - return SearchResponse.builder().response(projectfacilities).build(); } log.info("searching project facility using criteria"); - return projectFacilityRepository.findWithCount(projectFacilitySearchRequest.getProjectFacility(), + return projectFacilityRepository.find(projectFacilitySearchRequest.getProjectFacility(), limit, offset, tenantId, lastChangedSince, includeDeleted); } + } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java index 8f8c2555947..660efbd4814 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java @@ -5,7 +5,6 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectResource; import org.egov.common.models.project.ProjectResourceBulkRequest; import org.egov.common.models.project.ProjectResourceRequest; @@ -183,28 +182,27 @@ public List delete(ProjectResourceBulkRequest request, boolean } - public SearchResponse search(ProjectResourceSearchRequest request, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws QueryBuilderException { + public List search(ProjectResourceSearchRequest request, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws QueryBuilderException { String idFieldName = getIdFieldName(request.getProjectResource()); if (isSearchByIdOnly(request.getProjectResource(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod((Collections .singletonList(request.getProjectResource()))), request.getProjectResource()); - List projectResources = projectResourceRepository.findById(ids, includeDeleted, idFieldName).stream() + return projectResourceRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); - return SearchResponse.builder().response(projectResources).build(); } log.info("completed search method for project resource"); - return projectResourceRepository.findWithCount(request.getProjectResource(), + return projectResourceRepository.find(request.getProjectResource(), limit, offset, tenantId, lastChangedSince, includeDeleted); } } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java index e27c827ce29..56e2665792a 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java @@ -1,7 +1,7 @@ package org.egov.project.service; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import jakarta.validation.Valid; import java.util.Map; import lombok.extern.slf4j.Slf4j; diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java index d172b96263f..c600537a74e 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java @@ -4,7 +4,6 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.common.models.project.ProjectStaffRequest; @@ -29,7 +28,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.lang.reflect.Type; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Predicate; @@ -223,27 +224,26 @@ private Tuple, Map> validate(List return new Tuple<>(validEntities, errorDetailsMap); } - public SearchResponse search(ProjectStaffSearchRequest projectStaffSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public List search(ProjectStaffSearchRequest projectStaffSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("received request to search project staff"); if (isSearchByIdOnly(projectStaffSearchRequest.getProjectStaff())) { log.info("searching project staff by id"); List ids = projectStaffSearchRequest.getProjectStaff().getId(); log.info("fetching project staff with ids: {}", ids); - List projectStaffs = projectStaffRepository.findById(ids, includeDeleted).stream() + return projectStaffRepository.findById(ids, includeDeleted).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); - return SearchResponse.builder().response(projectStaffs).build(); } log.info("searching project staff using criteria"); - return projectStaffRepository.findWithCount(projectStaffSearchRequest.getProjectStaff(), + return projectStaffRepository.find(projectStaffSearchRequest.getProjectStaff(), limit, offset, tenantId, lastChangedSince, includeDeleted); } diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java index 6497beb4d53..2bd670f589f 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import java.util.Map; import java.util.ArrayList; import lombok.extern.slf4j.Slf4j; diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java index 97bdaecc500..db974db9be9 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java @@ -4,7 +4,7 @@ import java.util.Map; import java.util.stream.Collectors; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Address; import org.egov.common.models.project.Task; diff --git a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java index 2ac778f4891..3a0a08d31ea 100644 --- a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java @@ -1,26 +1,26 @@ package org.egov.project.util; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; +import digit.models.coremodels.RequestInfoWrapper; import lombok.extern.slf4j.Slf4j; +import net.minidev.json.JSONObject; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.egov.common.contract.models.RequestInfoWrapper; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.tracer.model.CustomException; -import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + @Component @Slf4j diff --git a/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java b/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java index be006ad385d..4de61e5ab79 100644 --- a/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java +++ b/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java @@ -5,10 +5,10 @@ import java.util.LinkedList; import java.util.List; -import org.egov.mdms.model.MasterDetail; -import org.egov.mdms.model.MdmsCriteria; -import org.egov.mdms.model.MdmsCriteriaReq; -import org.egov.mdms.model.ModuleDetail; +import digit.models.coremodels.mdms.MasterDetail; +import digit.models.coremodels.mdms.MdmsCriteria; +import digit.models.coremodels.mdms.MdmsCriteriaReq; +import digit.models.coremodels.mdms.ModuleDetail; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java b/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java index 8c9b810eecc..7d750e8d984 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import java.util.Iterator; import java.util.List; import java.util.Map; diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java index c0be5cfcb64..19c8454d63a 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java @@ -3,10 +3,10 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.mdms.model.MasterDetail; -import org.egov.mdms.model.MdmsCriteria; -import org.egov.mdms.model.MdmsCriteriaReq; -import org.egov.mdms.model.ModuleDetail; +import digit.models.coremodels.mdms.MasterDetail; +import digit.models.coremodels.mdms.MdmsCriteria; +import digit.models.coremodels.mdms.MdmsCriteriaReq; +import digit.models.coremodels.mdms.ModuleDetail; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; diff --git a/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java index a33408b813c..7491e024ec3 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java @@ -1,15 +1,9 @@ package org.egov.project.validator.staff; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - +import digit.models.coremodels.UserSearchRequest; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.User; -import org.egov.common.contract.user.UserSearchRequest; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; import org.egov.common.models.individual.Individual; @@ -24,6 +18,12 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import static org.egov.common.utils.CommonUtils.getIdToObjMap; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java index 0a4a68bd917..e3be161fabb 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java @@ -8,6 +8,10 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.mdms.MasterDetail; +import digit.models.coremodels.mdms.MdmsCriteria; +import digit.models.coremodels.mdms.MdmsCriteriaReq; +import digit.models.coremodels.mdms.ModuleDetail; import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.Error; @@ -18,10 +22,6 @@ import org.egov.common.service.MdmsService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; -import org.egov.mdms.model.MasterDetail; -import org.egov.mdms.model.MdmsCriteria; -import org.egov.mdms.model.MdmsCriteriaReq; -import org.egov.mdms.model.ModuleDetail; import org.egov.project.config.ProjectConfiguration; import org.egov.tracer.model.CustomException; import org.springframework.core.annotation.Order; diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java index 2ec0adc34d3..1b74b7ab1d7 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java @@ -220,7 +220,7 @@ public ResponseEntity projectFacilityV2SearchPost( @Valid @ModelAttribute URLParams urlParams, @ApiParam(value = "Capture details of Project facility.", required = true) @Valid @RequestBody ProjectFacilitySearchRequest projectFacilitySearchRequest ) throws Exception { - SearchResponse searchResponse = projectFacilityService.search( + List projectFacilities = projectFacilityService.search( projectFacilitySearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -229,8 +229,7 @@ public ResponseEntity projectFacilityV2SearchPost( urlParams.getIncludeDeleted() ); ProjectFacilityBulkResponse response = ProjectFacilityBulkResponse.builder() - .projectFacilities(searchResponse.getResponse()) - .totalCount(searchResponse.getTotalCount()) + .projectFacilities(projectFacilities) .responseInfo(ResponseInfoFactory .createResponseInfo(projectFacilitySearchRequest.getRequestInfo(), true)) .build(); @@ -311,7 +310,7 @@ public ResponseEntity projectStaffV1SearchPost( @Valid @ModelAttribute URLParams urlParams, @ApiParam(value = "Capture details of Project staff.", required = true) @Valid @RequestBody ProjectStaffSearchRequest projectStaffSearchRequest ) throws Exception { - SearchResponse searchResponse = projectStaffService.search( + List projectStaffList = projectStaffService.search( projectStaffSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -320,8 +319,7 @@ public ResponseEntity projectStaffV1SearchPost( urlParams.getIncludeDeleted() ); ProjectStaffBulkResponse response = ProjectStaffBulkResponse.builder() - .projectStaff(searchResponse.getResponse()) - .totalCount(searchResponse.getTotalCount()) + .projectStaff(projectStaffList) .responseInfo(ResponseInfoFactory .createResponseInfo(projectStaffSearchRequest.getRequestInfo(), true)) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java index ef0522cfbf0..6f71ea7ef93 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java @@ -7,7 +7,6 @@ import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; import org.egov.common.data.query.exception.QueryBuilderException; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.project.ProjectResource; import org.egov.common.models.project.ProjectResourceBulkRequest; @@ -76,7 +75,7 @@ public ResponseEntity resourceV1SearchPost( @ApiParam(value = "Search linkage of Project and resource.", required = true) @Valid @RequestBody ProjectResourceSearchRequest projectResourceSearchRequest ) throws QueryBuilderException { - SearchResponse searchResponse = projectResourceService.search( + List projectResource = projectResourceService.search( projectResourceSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -85,10 +84,7 @@ public ResponseEntity resourceV1SearchPost( urlParams.getIncludeDeleted() ); ProjectResourceBulkResponse response = ProjectResourceBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(projectResourceSearchRequest.getRequestInfo(), true)) - .projectResource(searchResponse.getResponse()) - .totalCount(searchResponse.getTotalCount()) - .build(); + .createResponseInfo(projectResourceSearchRequest.getRequestInfo(), true)).projectResource(projectResource).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index e27c6d18403..71af8eab0d3 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -184,4 +184,3 @@ project.task.no.resource.validation.status=ADMINISTRATION_FAILED, BENEFICIARY_RE #---------Attendance Feature ------------# project.attendance.feature.enabled=true - diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java index fccdb5d0d1d..93740830a51 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.mdms.model.MdmsCriteriaReq; +import digit.models.coremodels.mdms.MdmsCriteriaReq; import org.apache.commons.io.IOUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java index e4675e45bc2..805fba5c474 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.mdms.model.MdmsCriteriaReq; +import digit.models.coremodels.mdms.MdmsCriteriaReq; import org.apache.commons.io.IOUtils; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.core.SearchResponse; diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java index 85fd9f4e71b..6eed8465ca5 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java @@ -1,7 +1,6 @@ package org.egov.project.service; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectFacility; import org.egov.project.helper.ProjectFacilityTestBuilder; import org.egov.project.repository.ProjectFacilityRepository; @@ -47,9 +46,9 @@ void setUp() { @Test @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProjectFacilityFound() throws Exception { - when(projectFacilityRepository.findWithCount(any(ProjectFacilitySearch.class), any(Integer.class), + when(projectFacilityRepository.find(any(ProjectFacilitySearch.class), any(Integer.class), any(Integer.class), any(String.class), eq(null), any(Boolean.class))) - .thenReturn(SearchResponse.builder().response(Collections.emptyList()).build()); + .thenReturn(Collections.emptyList()); ProjectFacilitySearch projectFacilitySearch = ProjectFacilitySearch.builder() .id(Collections.singletonList("ID101")).facilityId(Collections.singletonList("some-facility-id")).build(); ProjectFacilitySearchRequest projectFacilitySearchRequest = ProjectFacilitySearchRequest.builder() @@ -78,9 +77,8 @@ void shouldNotRaiseExceptionIfNoProjectFacilityFoundForSearchById() { @Test @DisplayName("should return project facility if search criteria is matched") void shouldReturnProjectFacilityIfSearchCriteriaIsMatched() throws Exception { - when(projectFacilityRepository.findWithCount(any(ProjectFacilitySearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder() - .response(projectFacilities).build()); + when(projectFacilityRepository.find(any(ProjectFacilitySearch.class), any(Integer.class), + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectFacilities); projectFacilities.add(ProjectFacilityTestBuilder.builder().withId().withId().withAuditDetails().build()); ProjectFacilitySearch projectFacilitySearch = ProjectFacilitySearch.builder() .id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-projectId")).build(); @@ -89,7 +87,7 @@ void shouldReturnProjectFacilityIfSearchCriteriaIsMatched() throws Exception { .withCompleteRequestInfo().build()).build(); List projectFacilities = projectFacilityService.search(projectFacilitySearchRequest, - 10, 0, "default", null, false).getResponse(); + 10, 0, "default", null, false); assertEquals(1, projectFacilities.size()); } @@ -106,7 +104,7 @@ void shouldReturnFromCacheIfSearchCriteriaHasIdOnly() throws Exception { when(projectFacilityRepository.findById(anyList(), anyBoolean())).thenReturn(projectFacilities); List projectFacilities = projectFacilityService.search(projectFacilitySearchRequest, - 10, 0, null, null, true).getResponse(); + 10, 0, null, null, true); assertEquals(1, projectFacilities.size()); } diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java index f14fa8f9a9e..36aa7100f8d 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java @@ -1,7 +1,6 @@ package org.egov.project.service; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectStaff; import org.egov.project.helper.ProjectStaffTestBuilder; import org.egov.project.repository.ProjectStaffRepository; @@ -47,9 +46,9 @@ void setUp() { @Test @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProjectStaffFound() throws Exception { - when(projectStaffRepository.findWithCount(any(ProjectStaffSearch.class), any(Integer.class), + when(projectStaffRepository.find(any(ProjectStaffSearch.class), any(Integer.class), any(Integer.class), any(String.class), eq(null), any(Boolean.class))) - .thenReturn(SearchResponse.builder().response(Collections.emptyList()).build()); + .thenReturn(Collections.emptyList()); ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder() .id(Collections.singletonList("ID101")).staffId(Collections.singletonList("some-user-id")).build(); ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder() @@ -76,15 +75,15 @@ void shouldNotRaiseExceptionIfNoProjectStaffFoundForSearchById() { @Test @DisplayName("should return project staff if search criteria is matched") void shouldReturnProjectStaffIfSearchCriteriaIsMatched() throws Exception { - when(projectStaffRepository.findWithCount(any(ProjectStaffSearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().response(projectStaffs).build()); + when(projectStaffRepository.find(any(ProjectStaffSearch.class), any(Integer.class), + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectStaffs); projectStaffs.add(ProjectStaffTestBuilder.builder().withId().withId().withAuditDetails().build()); ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder().id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-projectId")).build(); ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder() .projectStaff(projectStaffSearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); - List projectStaffs = projectStaffService.search(projectStaffSearchRequest, 10, 0, "default", null, false).getResponse(); + List projectStaffs = projectStaffService.search(projectStaffSearchRequest, 10, 0, "default", null, false); assertEquals(1, projectStaffs.size()); } @@ -101,7 +100,7 @@ void shouldReturnFromCacheIfSearchCriteriaHasIdOnly() throws Exception { when(projectStaffRepository.findById(anyList(), anyBoolean())).thenReturn(projectStaffs); List projectStaffs = projectStaffService.search(projectStaffSearchRequest, - 10, 0, null, null, true).getResponse(); + 10, 0, null, null, true); assertEquals(1, projectStaffs.size()); } diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java index fe6a8e402db..e6a97cf70c8 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectFacility; import org.egov.common.models.project.ProjectFacilityBulkRequest; import org.egov.common.models.project.ProjectFacilityBulkResponse; @@ -194,9 +193,8 @@ void shouldAcceptSearchRequestAndReturnProjectFacility() throws Exception { any(Integer.class), any(String.class), any(Long.class), - any(Boolean.class))).thenReturn(SearchResponse.builder() - .response(Arrays.asList(ProjectFacilityTestBuilder.builder() - .withId().withAuditDetails().build())).build()); + any(Boolean.class))).thenReturn(Arrays.asList(ProjectFacilityTestBuilder.builder() + .withId().withAuditDetails().build())); final MvcResult result = mockMvc.perform(post( "/facility/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java index 2147e98e460..1e1b5409485 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkResponse; import org.egov.common.models.project.ProjectStaffRequest; @@ -176,7 +175,7 @@ void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { any(Integer.class), any(String.class), any(Long.class), - any(Boolean.class))).thenReturn(SearchResponse.builder().response(Arrays.asList(ProjectStaffTestBuilder.builder().withId().withAuditDetails().build())).build()); + any(Boolean.class))).thenReturn(Arrays.asList(ProjectStaffTestBuilder.builder().withId().withAuditDetails().build())); final MvcResult result = mockMvc.perform(post( "/staff/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md index a1f5546b24e..21e78657688 100644 --- a/health-services/referralmanagement/CHANGELOG.md +++ b/health-services/referralmanagement/CHANGELOG.md @@ -3,7 +3,6 @@ All notable changes to this module will be documented in this file. ## 1.0.3 - 2024-08-09 - Upgraded downsync logic. -- Added `ExistentEntityValidator` fixes ## 1.0.2 - 2024-05-29 diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index 4bf32a9765a..b9d85ad8269 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -46,12 +46,12 @@ org.egov.common health-services-common - 1.0.20-dev-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common health-services-models - 1.0.23-dev-SNAPSHOT + 1.0.20-SNAPSHOT compile diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java index 0fee8b9d853..d2d43634030 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java @@ -12,7 +12,6 @@ import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearch; import org.egov.common.producer.Producer; @@ -24,7 +23,6 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; -import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; /** @@ -68,7 +66,7 @@ protected HFReferralRepository(Producer producer, NamedParameterJdbcTemplate nam * @param includeDeleted Flag indicating whether to include deleted records. * @return A list of HFReferral entities matching the search criteria. */ - public SearchResponse find(HFReferralSearch searchObject, Integer limit, Integer offset, String tenantId, + public List find(HFReferralSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) { // Initial query to select HFReferral fields from the table. String query = "SELECT hf.id, hf.clientreferenceid, hf.tenantid, hf.projectid, hf.projectfacilityid, hf.symptom, hf.symptomsurveyid, hf.beneficiaryid, hf.referralcode, hf.nationallevelid, hf.createdby, hf.createdtime, hf.lastmodifiedby, hf.lastmodifiedtime, hf.clientcreatedby, hf.clientcreatedtime, hf.clientlastmodifiedby, hf.clientlastmodifiedtime, hf.rowversion, hf.isdeleted, hf.additionaldetails from hf_referral hf"; @@ -98,21 +96,16 @@ public SearchResponse find(HFReferralSearch searchObject, Integer li } // Add ORDER BY, LIMIT, and OFFSET clauses to the query. - query = query + "ORDER BY hf.createdtime DESC"; + query = query + "ORDER BY hf.createdtime DESC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); - - Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); - - query += " LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); // Execute the query and retrieve the list of HFReferral entities. List hfReferralList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); - - return SearchResponse.builder().response(hfReferralList).totalCount(totalCount).build(); + return hfReferralList; } /** @@ -123,7 +116,7 @@ public SearchResponse find(HFReferralSearch searchObject, Integer li * @param columnName The column name to search for IDs. * @return A list of HFReferral entities matching the provided IDs. */ - public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { + public List findById(List ids, Boolean includeDeleted, String columnName) { // Find objects in the cache based on the provided IDs. List objFound = findInCache(ids); if (!includeDeleted) { @@ -141,7 +134,7 @@ public SearchResponse findById(List ids, String columnName, // If no IDs are remaining, return the objects found in the cache. if (ids.isEmpty()) { - return SearchResponse.builder().response(objFound).build(); + return objFound; } } @@ -161,6 +154,6 @@ public SearchResponse findById(List ids, String columnName, // Add the retrieved entities to the cache. objFound.addAll(hfReferralList); putInCache(objFound); - return SearchResponse.builder().response(objFound).build(); + return objFound; } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java index 7994e3d192f..5456cd9179c 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java index 83971874a2f..181aa1b6a55 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java index 4b4d961b1f2..3832d8bd7e3 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java index bc6aa52dc33..c3c287bcff3 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java @@ -9,7 +9,6 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; import org.egov.common.models.referralmanagement.hfreferral.HFReferralRequest; @@ -170,12 +169,12 @@ public List update(HFReferralBulkRequest hfReferralRequest, boolean } // Method to search for HFReferrals based on certain criteria - public SearchResponse search(HFReferralSearchRequest referralSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) { + public List search(HFReferralSearchRequest referralSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { log.info("Received request to search referrals"); String idFieldName = getIdFieldName(referralSearchRequest.getHfReferral()); @@ -187,12 +186,11 @@ public SearchResponse search(HFReferralSearchRequest referralSearchR referralSearchRequest.getHfReferral()); log.info("Fetching referrals with IDs: {}", ids); - List hfReferrals = hfReferralRepository.findById(ids, idFieldName, includeDeleted).getResponse().stream() + return hfReferralRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); - return SearchResponse.builder().response(hfReferrals).build(); } log.info("Searching referrals using criteria"); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java index c812f7c5021..3c09df3edde 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java @@ -1,18 +1,19 @@ package org.egov.referralmanagement.service; - import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - - -import com.jayway.jsonpath.JsonPath; import java.util.function.Function; import java.util.stream.Collectors; +import com.jayway.jsonpath.JsonPath; +import digit.models.coremodels.mdms.MasterDetail; +import digit.models.coremodels.mdms.MdmsCriteria; +import digit.models.coremodels.mdms.MdmsCriteriaReq; +import digit.models.coremodels.mdms.ModuleDetail; import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; @@ -21,11 +22,6 @@ import org.egov.common.models.project.ProjectResponse; import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncCriteria; import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; -import org.egov.mdms.model.MasterDetail; -import org.egov.mdms.model.MdmsCriteria; -import org.egov.mdms.model.MdmsCriteriaReq; -import org.egov.mdms.model.ModuleDetail; - import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java index 3541cb2d4dc..043c7d6a1b5 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java @@ -1,7 +1,7 @@ package org.egov.referralmanagement.util; +import digit.models.coremodels.UserSearchRequest; import org.egov.common.contract.request.RequestInfo; -import org.egov.common.contract.user.UserSearchRequest; import org.egov.common.service.UserService; import org.springframework.util.CollectionUtils; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java index d7e81c7e9a4..3011cef48ce 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java @@ -82,8 +82,7 @@ public Map> validate(HFReferralBulkRequest request) { try { // Query the repository to find existing entities existingReferrals = hfReferralRepository.find(hfReferralSearch, hfReferrals.size(), 0, - hfReferrals.get(0).getTenantId(), null, false).getResponse() - ; + hfReferrals.get(0).getTenantId(), null, false); } catch (Exception e) { // Handle query builder exception log.error("Search failed for HFReferral with error: {}", e.getMessage(), e); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java index 83011aceec9..e5d62bfee0a 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java @@ -61,7 +61,7 @@ public Map> validate(HFReferralBulkRequest request) { if (!iMap.isEmpty()) { List hfReferralIds = new ArrayList<>(iMap.keySet()); List existingHfReferrals = hfReferralRepository.findById(hfReferralIds, - getIdFieldName(idMethod), false).getResponse(); + false, getIdFieldName(idMethod)); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingHfReferrals, idMethod); entitiesWithMismatchedRowVersion.forEach(hfReferral -> { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java index c09a02bebfa..f09a4c578e8 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java @@ -6,7 +6,6 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; @@ -108,7 +107,7 @@ public ResponseEntity referralV1SearchPost( @ApiParam(value = "HFReferral Search.", required = true) @Valid @RequestBody HFReferralSearchRequest request ) throws Exception { - SearchResponse searchResponse = hfReferralService.search( + List hfReferrals = hfReferralService.search( request, urlParams.getLimit(), urlParams.getOffset(), @@ -116,10 +115,7 @@ public ResponseEntity referralV1SearchPost( urlParams.getLastChangedSince(), urlParams.getIncludeDeleted()); HFReferralBulkResponse response = HFReferralBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .hfReferrals(searchResponse.getResponse()) - .totalCount(searchResponse.getTotalCount()) - .build(); + .createResponseInfo(request.getRequestInfo(), true)).hfReferrals(hfReferrals).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java index 7200f29cecc..41e91448569 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -39,6 +39,9 @@ public class ServiceConstants { public static final String FILE_NOT_FOUND_CODE = "FILE_NOT_FOUND"; public static final String FILE_NOT_FOUND_MESSAGE = "No file with the specified templateIdentifier found - "; + public static final String PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE = "PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT"; + public static final String PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE = "Key is not present in json object - "; + public static final String UNABLE_TO_CREATE_ADDITIONAL_DETAILS_CODE = "UNABLE_TO_CREATE_ADDITIONAL_DETAILS"; public static final String UNABLE_TO_CREATE_ADDITIONAL_DETAILS_MESSAGE = "Unable to create additional details for facility creation."; @@ -116,8 +119,16 @@ public class ServiceConstants { public static final String SOURCE_KEY = "source"; public static final String MICROPLAN_SOURCE_KEY = "microplan"; public static final String MICROPLAN_ID_KEY = "microplanId"; + public static final String FACILITY_NAME = "facilityName"; + public static final String HCM_MICROPLAN_SERVING_FACILITY = "HCM_MICROPLAN_SERVING_FACILITY"; //Census additional field constants public static final String UPLOADED_KEY = "UPLOADED_"; public static final String CONFIRMED_KEY = "CONFIRMED_"; + + //Excel header row styling constants + public static final String HEX_BACKGROUND_COLOR = "93C47D"; // Constant background color + public static final boolean FREEZE_CELL = true; // Constant to lock cell + public static final int COLUMN_WIDTH = 40; // Column width in characters + } diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java index 6f2326d628a..2faa00b43f5 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java @@ -13,7 +13,6 @@ import org.egov.processor.config.ServiceConstants; import org.egov.processor.util.*; import org.egov.processor.web.models.*; -import org.egov.processor.web.models.Locale; import org.egov.processor.web.models.boundary.BoundarySearchResponse; import org.egov.processor.web.models.boundary.EnrichedBoundary; import org.egov.processor.web.models.campaignManager.Boundary; @@ -31,9 +30,6 @@ import java.util.*; import java.util.stream.Collectors; -import static org.egov.processor.config.ServiceConstants.HCM_ADMIN_CONSOLE_BOUNDARY_DATA; -import static org.egov.processor.config.ServiceConstants.READ_ME_SHEET_NAME; - @Slf4j @Service public class ExcelParser implements FileParser { @@ -64,9 +60,11 @@ public class ExcelParser implements FileParser { private PlanConfigurationUtil planConfigurationUtil; + private OutputEstimationGenerationUtil outputEstimationGenerationUtil; + public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, - Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil, LocaleUtil localeUtil, CensusUtil censusUtil, EnrichmentUtil enrichmentUtil, PlanConfigurationUtil planConfigurationUtil) { + Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil, LocaleUtil localeUtil, CensusUtil censusUtil, EnrichmentUtil enrichmentUtil, PlanConfigurationUtil planConfigurationUtil, OutputEstimationGenerationUtil outputEstimationGenerationUtil) { this.objectMapper = objectMapper; this.parsingUtil = parsingUtil; this.filestoreUtil = filestoreUtil; @@ -80,6 +78,7 @@ public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, Filestore this.censusUtil = censusUtil; this.enrichmentUtil = enrichmentUtil; this.planConfigurationUtil = planConfigurationUtil; + this.outputEstimationGenerationUtil = outputEstimationGenerationUtil; } /** @@ -128,7 +127,7 @@ private void processExcelFile(PlanConfigurationRequest planConfigurationRequest, processSheets(planConfigurationRequest, fileStoreId, campaignResponse, workbook, campaignBoundaryList, dataFormatter); uploadFileAndIntegrateCampaign(planConfigurationRequest, campaignResponse, - workbook, campaignBoundaryList, campaignResourcesList); + workbook, campaignBoundaryList, campaignResourcesList, fileStoreId); } catch (FileNotFoundException e) { log.error("File not found: {}", e.getMessage()); throw new CustomException("FileNotFound", "The specified file was not found."); @@ -153,7 +152,7 @@ private void processExcelFile(PlanConfigurationRequest planConfigurationRequest, */ private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigurationRequest, Object campaignResponse, Workbook workbook, - List campaignBoundaryList, List campaignResourcesList) { + List campaignBoundaryList, List campaignResourcesList, String filestoreId) { File fileToUpload = null; try { PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); @@ -164,9 +163,21 @@ private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigu planUtil.update(planConfigurationRequest); } if (planConfig.getStatus().equals(config.getPlanConfigUpdatePlanEstimatesIntoOutputFileStatus()) && config.isIntegrateWithAdminConsole()) { + //Upload the processed output file into project factory String uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); campaignIntegrationUtil.updateResourcesInProjectFactory(planConfigurationRequest, uploadedFileStoreId); - } + + outputEstimationGenerationUtil.processOutputFile(workbook, planConfigurationRequest); + + // Adding facility information for each boundary code + outputEstimationGenerationUtil.addAssignedFacility(workbook, planConfigurationRequest, filestoreId); + + //update processed output file into plan configuration file object + fileToUpload = convertWorkbookToXls(workbook); + uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); + planUtil.setFileStoreIdForPopulationTemplate(planConfigurationRequest, uploadedFileStoreId); + planUtil.update(planConfigurationRequest); + } } finally { try { if (fileToUpload != null && !fileToUpload.delete()) { @@ -189,7 +200,7 @@ private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigu * @param campaignBoundaryList List of boundary objects related to the campaign. * @param dataFormatter The data formatter for formatting cell values. */ - + //TODO: processsheetforestimate and processsheetforcensus private void processSheets(PlanConfigurationRequest request, String fileStoreId, Object campaignResponse, Workbook excelWorkbook, List campaignBoundaryList, @@ -213,7 +224,7 @@ private void processSheets(PlanConfigurationRequest request, String fileStoreId, LinkedHashMap::new )); excelWorkbook.forEach(excelWorkbookSheet -> { - if (isSheetAllowedToProcess(request, excelWorkbookSheet.getSheetName(), localeResponse)) { + if (parsingUtil.isSheetAllowedToProcess(request, excelWorkbookSheet.getSheetName(), localeResponse)) { if (request.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerPlanEstimatesStatus())) { enrichmentUtil.enrichsheetWithApprovedCensusRecords(excelWorkbookSheet, request, fileStoreId, mappedValues); processRows(request, excelWorkbookSheet, dataFormatter, fileStoreId, @@ -312,7 +323,6 @@ private List getBoundaryCodeList(PlanConfigurationRequest planConfigurat * @return A map of attribute names to their corresponding indices or data types. */ - //TODO: fetch from adminSchema master private Map prepareAttributeVsIndexMap(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, CampaignResponse campaign, PlanConfiguration planConfig, Object mdmsData) { @@ -370,7 +380,8 @@ private void performRowLevelCalculations(PlanConfigurationRequest planConfigurat campaignIntegrationUtil.updateCampaignBoundary(planConfig, feature, assumptionValueMap, mappedValues, mapOfColumnNameAndIndex, campaignBoundaryList, resultMap); planUtil.create(planConfigurationRequest, feature, resultMap, mappedValues); - + // TODO: remove after testing + parsingUtil.printRow(sheet, row); } } @@ -718,28 +729,5 @@ public List getAllBoundaryPresentforHierarchyType(List return boundaryList; } - /** - * Checks if a sheet is allowed to be processed based on MDMS constants and locale-specific configuration. - * - * @param planConfigurationRequest The request containing configuration details including request info and tenant ID. - * @param sheetName The name of the sheet to be processed. - * @return true if the sheet is allowed to be processed, false otherwise. - * @throws JsonMappingException If there's an issue mapping JSON response to Java objects. - * @throws JsonProcessingException If there's an issue processing JSON during conversion. - */ - private boolean isSheetAllowedToProcess(PlanConfigurationRequest planConfigurationRequest, String sheetName, LocaleResponse localeResponse) { - Map mdmsDataConstants = mdmsUtil.fetchMdmsDataForCommonConstants( - planConfigurationRequest.getRequestInfo(), - planConfigurationRequest.getPlanConfiguration().getTenantId()); - - for (Locale locale : localeResponse.getMessages()) { - if ((locale.getCode().equalsIgnoreCase((String) mdmsDataConstants.get(READ_ME_SHEET_NAME))) - || locale.getCode().equalsIgnoreCase(HCM_ADMIN_CONSOLE_BOUNDARY_DATA)) { - if (sheetName.equals(locale.getMessage())) - return false; - } - } - return true; - } } \ No newline at end of file diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java index 89f0a89511b..e543dd062a3 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java @@ -144,6 +144,9 @@ public void enrichsheetWithApprovedCensusRecords(Sheet sheet, PlanConfigurationR } } } + //TODO: remove after testing + log.info("After updating values in sheet -> "); + parsingUtil.printRow(sheet, row); log.info("Successfully update file with approved census data."); } @@ -220,10 +223,10 @@ public void enrichsheetWithApprovedPlanEstimates(Sheet sheet, PlanConfigurationR Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); - //Getting census records for the list of boundaryCodes + //Getting plan records for the list of boundaryCodes List planList = getPlanRecordsForEnrichment(planConfigurationRequest, boundaryCodes); - // Create a map from boundaryCode to Census for quick lookups + // Create a map from boundaryCode to Plan for quick lookups Map planMap = planList.stream() .collect(Collectors.toMap(Plan::getLocality, plan -> plan)); @@ -233,6 +236,7 @@ public void enrichsheetWithApprovedPlanEstimates(Sheet sheet, PlanConfigurationR for(Row row: sheet) { + parsingUtil.printRow(sheet, row); // Skip the header row and empty rows if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { continue; @@ -265,6 +269,9 @@ public void enrichsheetWithApprovedPlanEstimates(Sheet sheet, PlanConfigurationR } } } + //TODO: remove after testing + log.info("After updating values in sheet -> "); + parsingUtil.printRow(sheet, row); log.info("Successfully update file with approved census data."); } diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java index ba10327e4c8..756252b562a 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java @@ -7,8 +7,8 @@ import org.apache.commons.io.FileUtils; import org.apache.poi.ss.usermodel.*; import org.egov.processor.config.ServiceConstants; -import org.egov.processor.web.models.PlanConfiguration; -import org.egov.processor.web.models.ResourceMapping; +import org.egov.processor.web.models.Locale; +import org.egov.processor.web.models.*; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; @@ -17,6 +17,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.*; @@ -24,7 +25,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import static org.egov.processor.config.ServiceConstants.PROPERTIES; +import static org.egov.processor.config.ServiceConstants.*; @Slf4j @Component @@ -36,10 +37,16 @@ public class ParsingUtil { private CalculationUtil calculationUtil; - public ParsingUtil(PlanConfigurationUtil planConfigurationUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil) { + private MdmsUtil mdmsUtil; + + private ObjectMapper objectMapper; + + public ParsingUtil(PlanConfigurationUtil planConfigurationUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil, MdmsUtil mdmsUtil, ObjectMapper objectMapper) { this.planConfigurationUtil = planConfigurationUtil; this.filestoreUtil = filestoreUtil; this.calculationUtil = calculationUtil; + this.mdmsUtil = mdmsUtil; + this.objectMapper = objectMapper; } public List fetchAttributeNamesFromJson(JsonNode jsonNode) @@ -314,7 +321,7 @@ public List extractPropertyNamesFromAdminSchema(JsonNode rootNode) { * @param row the Row to check * @return true if the row is empty, false otherwise */ - public static boolean isRowEmpty(Row row) { + public boolean isRowEmpty(Row row) { if (row == null) { return true; } @@ -392,4 +399,60 @@ public void printRow(Sheet sheet, Row row) { System.out.println(); // Move to the next line after printing the row } + /** + * Checks if a sheet is allowed to be processed based on MDMS constants and locale-specific configuration. + * + * @param planConfigurationRequest The request containing configuration details including request info and tenant ID. + * @param sheetName The name of the sheet to be processed. + * @return true if the sheet is allowed to be processed, false otherwise. + */ + public boolean isSheetAllowedToProcess(PlanConfigurationRequest planConfigurationRequest, String sheetName, LocaleResponse localeResponse) { + Map mdmsDataConstants = mdmsUtil.fetchMdmsDataForCommonConstants( + planConfigurationRequest.getRequestInfo(), + planConfigurationRequest.getPlanConfiguration().getTenantId()); + + for (Locale locale : localeResponse.getMessages()) { + if ((locale.getCode().equalsIgnoreCase((String) mdmsDataConstants.get(READ_ME_SHEET_NAME))) + || locale.getCode().equalsIgnoreCase(HCM_ADMIN_CONSOLE_BOUNDARY_DATA)) { + if (sheetName.equals(locale.getMessage())) + return false; + } + } + return true; + + } + + /** + * Extracts provided field from the additional details object + * + * @param additionalDetails the additionalDetails object from PlanConfigurationRequest + * @param fieldToExtract the name of the field to be extracted from the additional details + * @return the value of the specified field as a string + * @throws CustomException if the field does not exist + */ + public Object extractFieldsFromJsonObject(Object additionalDetails, String fieldToExtract) { + try { + String jsonString = objectMapper.writeValueAsString(additionalDetails); + JsonNode rootNode = objectMapper.readTree(jsonString); + + JsonNode node = rootNode.get(fieldToExtract); + if (node != null && !node.isNull()) { + + // Check for different types of JSON nodes + if (node.isDouble() || node.isFloat()) { + return BigDecimal.valueOf(node.asDouble()); // Convert Double to BigDecimal + } else if (node.isLong() || node.isInt()) { + return BigDecimal.valueOf(node.asLong()); // Convert Long to BigDecimal + } else if (node.isBoolean()) { + return node.asBoolean(); + } else if (node.isTextual()) { + return node.asText(); + } + } + return null; + } catch (Exception e) { + log.error(e.getMessage() + fieldToExtract); + throw new CustomException(PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE, PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE + fieldToExtract); + } + } } diff --git a/health-services/stock/CHANGELOG.md b/health-services/stock/CHANGELOG.md index de3d5826f7a..564823f17b1 100644 --- a/health-services/stock/CHANGELOG.md +++ b/health-services/stock/CHANGELOG.md @@ -8,7 +8,6 @@ All notable changes to this module will be documented in this file. - Upgraded PostgresSQL Driver version to 42.7.1 - Upgraded Flyway base image version to 10.7.1 for DB Migration - Upgraded Flyway-Core to 9.22.3 -- Added `ExistentEntityValidator` fixes ## 1.1.2 - 2024-02-26 - Enhance inventory flow with sender id and receiver id added. diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 5cb0c17da56..d204ba58903 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.20-dev-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common health-services-models - 1.0.23-dev-SNAPSHOT + 1.0.20-SNAPSHOT diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java index d05bca6fdd1..813246f8a2b 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.stock.StockReconciliation; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index ea57dbad66d..e413a3052ac 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.common.contract.models.AuditDetails; +import digit.models.coremodels.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.stock.ReferenceIdType; import org.egov.common.models.stock.SenderReceiverType; diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java index 69340c5efca..6c6801a5922 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java @@ -10,7 +10,6 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; import org.egov.common.models.stock.StockReconciliationRequest; @@ -183,27 +182,26 @@ public List delete(StockReconciliationBulkRequest request, return validEntities; } - public SearchResponse search(StockReconciliationSearchRequest request, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public List search(StockReconciliationSearchRequest request, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("starting search method for stock reconciliation"); String idFieldName = getIdFieldName(request.getStockReconciliation()); if (isSearchByIdOnly(request.getStockReconciliation(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(request.getStockReconciliation())), request.getStockReconciliation()); - List stockReconciliations = stockRepository.findById(ids, includeDeleted, idFieldName).stream() + return stockRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); - return SearchResponse.builder().response(stockReconciliations).build(); } log.info("completed search method for stock reconciliation"); - return stockRepository.findWithCount(request.getStockReconciliation(), + return stockRepository.find(request.getStockReconciliation(), limit, offset, tenantId, lastChangedSince, includeDeleted); } } diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java index c6b60278be7..6a26da44ced 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java @@ -10,7 +10,6 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.common.models.stock.StockRequest; @@ -178,28 +177,27 @@ public List delete(StockBulkRequest request, boolean isBulk) { return validEntities; } - public SearchResponse search(StockSearchRequest stockSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public List search(StockSearchRequest stockSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("starting search method for stock"); String idFieldName = getIdFieldName(stockSearchRequest.getStock()); if (isSearchByIdOnly(stockSearchRequest.getStock(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(stockSearchRequest.getStock())), stockSearchRequest.getStock()); - List stocks = stockRepository.findById(ids, includeDeleted, idFieldName).stream() + return stockRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); - return SearchResponse.builder().response(stocks).build(); } log.info("completed search method for stock"); - return stockRepository.findWithCount(stockSearchRequest.getStock(), + return stockRepository.find(stockSearchRequest.getStock(), limit, offset, tenantId, lastChangedSince, includeDeleted); } } diff --git a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java index 5c436e37811..402f6fa3414 100644 --- a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java +++ b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java @@ -6,8 +6,8 @@ import java.util.Map; import java.util.stream.Collectors; +import digit.models.coremodels.UserSearchRequest; import org.egov.common.contract.request.RequestInfo; -import org.egov.common.contract.user.UserSearchRequest; import org.egov.common.ds.Tuple; import org.egov.common.models.Error; import org.egov.common.models.stock.SenderReceiverType; diff --git a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java index 7033f50a14a..913213dd191 100644 --- a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java +++ b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java @@ -8,7 +8,6 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; @@ -81,7 +80,7 @@ public ResponseEntity stockV1SearchPost( @ApiParam(value = "Capture details of Stock Transfer.", required = true) @Valid @RequestBody StockSearchRequest stockSearchRequest ) throws Exception { - SearchResponse searchResponse = stockService.search( + List stock = stockService.search( stockSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -90,7 +89,7 @@ public ResponseEntity stockV1SearchPost( urlParams.getIncludeDeleted() ); StockBulkResponse response = StockBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(stockSearchRequest.getRequestInfo(), true)).stock(searchResponse.getResponse()).totalCount(searchResponse.getTotalCount()).build(); + .createResponseInfo(stockSearchRequest.getRequestInfo(), true)).stock(stock).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java index 41fc33437e9..e612c3b692f 100644 --- a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java +++ b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java @@ -7,7 +7,6 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.core.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; @@ -78,7 +77,7 @@ public ResponseEntity stockReconciliationV1Sear @ApiParam(value = "Capture details of Stock Reconciliation.", required = true) @Valid @RequestBody StockReconciliationSearchRequest stockReconciliationSearchRequest ) throws Exception { - SearchResponse searchResponse = stockReconciliationService.search( + List stock = stockReconciliationService.search( stockReconciliationSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -87,10 +86,7 @@ public ResponseEntity stockReconciliationV1Sear urlParams.getIncludeDeleted() ); StockReconciliationBulkResponse response = StockReconciliationBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(stockReconciliationSearchRequest.getRequestInfo(), true)) - .stockReconciliation(searchResponse.getResponse()) - .totalCount(searchResponse.getTotalCount()) - .build(); + .createResponseInfo(stockReconciliationSearchRequest.getRequestInfo(), true)).stockReconciliation(stock).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } From 06779ff180b519e6dde0906d8b05abd4b5eceedb Mon Sep 17 00:00:00 2001 From: Priyanka-eGov Date: Mon, 6 Jan 2025 16:02:48 +0530 Subject: [PATCH 29/29] HCMPRE-1801 setting dynamic column width for column headers --- .../egov/processor/util/ExcelStylingUtil.java | 26 +++++++++++++++++-- .../util/OutputEstimationGenerationUtil.java | 2 ++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/ExcelStylingUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/ExcelStylingUtil.java index c8da424ea1b..f24e7bd2fdd 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/ExcelStylingUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/ExcelStylingUtil.java @@ -42,9 +42,31 @@ public void styleCell(Cell cell) { // Apply the style to the cell cell.setCellStyle(cellStyle); - // Adjust the column width + } + + /** + * Adjusts the column width to fit the content of the given cell, adding padding for readability. + * + * @param cell the cell whose column width is to be adjusted; does nothing if null. + */ + public void adjustColumnWidthForCell(Cell cell) { + if (cell == null) { + return; + } + + Sheet sheet = cell.getSheet(); int columnIndex = cell.getColumnIndex(); - sheet.setColumnWidth(columnIndex, COLUMN_WIDTH * 256); // Width is measured in units of 1/256 of a character + int maxWidth = sheet.getColumnWidth(columnIndex); + + // Calculate the width needed for the current cell content + String cellValue = cell.toString(); // Convert cell content to string + int cellWidth = cellValue.length() * 256; // Approximate width (1/256th of character width) + + // Use the maximum width seen so far, including padding for readability + int padding = 512; // Adjust padding as needed + int newWidth = Math.max(maxWidth, cellWidth + padding); + + sheet.setColumnWidth(columnIndex, newWidth); } /** diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java index 71b3ac8b656..6e4c828e823 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java @@ -81,6 +81,7 @@ public void processSheetForHeaderLocalization(Sheet sheet, Map l // Update the cell value with the localized message excelStylingUtil.styleCell(headerColumn); headerColumn.setCellValue(localizationCodeAndMessageMap.get(headerColumnValue)); + excelStylingUtil.adjustColumnWidthForCell(headerColumn); } } @@ -190,6 +191,7 @@ private int createAssignedFacilityColumn(Sheet sheet, String assignedFacilityCol Cell facilityColHeader = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); excelStylingUtil.styleCell(facilityColHeader); facilityColHeader.setCellValue(assignedFacilityColHeader); + excelStylingUtil.adjustColumnWidthForCell(facilityColHeader); return indexOfFacility; } }